aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/rc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/rc')
-rw-r--r--drivers/media/rc/Kconfig193
-rw-r--r--drivers/media/rc/Makefile22
-rw-r--r--drivers/media/rc/ene_ir.c1208
-rw-r--r--drivers/media/rc/ene_ir.h261
-rw-r--r--drivers/media/rc/imon.c2457
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c198
-rw-r--r--drivers/media/rc/ir-lirc-codec.c402
-rw-r--r--drivers/media/rc/ir-nec-decoder.c220
-rw-r--r--drivers/media/rc/ir-raw.c371
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c189
-rw-r--r--drivers/media/rc/ir-rc5-sz-decoder.c153
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c280
-rw-r--r--drivers/media/rc/ir-sony-decoder.c181
-rw-r--r--drivers/media/rc/keymaps/Kconfig15
-rw-r--r--drivers/media/rc/keymaps/Makefile88
-rw-r--r--drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c89
-rw-r--r--drivers/media/rc/keymaps/rc-alink-dtu-m.c68
-rw-r--r--drivers/media/rc/keymaps/rc-anysee.c93
-rw-r--r--drivers/media/rc/keymaps/rc-apac-viewcomp.c80
-rw-r--r--drivers/media/rc/keymaps/rc-asus-pc39.c91
-rw-r--r--drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c69
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-a16d.c75
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-cardbus.c97
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-dvbt.c78
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m135a.c147
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c95
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-rm-ks.c79
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia.c86
-rw-r--r--drivers/media/rc/keymaps/rc-avertv-303.c85
-rw-r--r--drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c102
-rw-r--r--drivers/media/rc/keymaps/rc-behold-columbus.c108
-rw-r--r--drivers/media/rc/keymaps/rc-behold.c141
-rw-r--r--drivers/media/rc/keymaps/rc-budget-ci-old.c92
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy-1400.c84
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy.c78
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-nec.c124
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-rc5.c235
-rw-r--r--drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c98
-rw-r--r--drivers/media/rc/keymaps/rc-digittrade.c82
-rw-r--r--drivers/media/rc/keymaps/rc-dm1105-nec.c76
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c78
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c97
-rw-r--r--drivers/media/rc/keymaps/rc-em-terratec.c69
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv-fm53.c81
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv.c112
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv2.c90
-rw-r--r--drivers/media/rc/keymaps/rc-evga-indtube.c61
-rw-r--r--drivers/media/rc/keymaps/rc-eztv.c96
-rw-r--r--drivers/media/rc/keymaps/rc-flydvb.c77
-rw-r--r--drivers/media/rc/keymaps/rc-flyvideo.c70
-rw-r--r--drivers/media/rc/keymaps/rc-fusionhdtv-mce.c98
-rw-r--r--drivers/media/rc/keymaps/rc-gadmei-rm008z.c81
-rw-r--r--drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c84
-rw-r--r--drivers/media/rc/keymaps/rc-gotview7135.c79
-rw-r--r--drivers/media/rc/keymaps/rc-hauppauge-new.c100
-rw-r--r--drivers/media/rc/keymaps/rc-imon-mce.c142
-rw-r--r--drivers/media/rc/keymaps/rc-imon-pad.c156
-rw-r--r--drivers/media/rc/keymaps/rc-iodata-bctv7e.c88
-rw-r--r--drivers/media/rc/keymaps/rc-kaiomy.c87
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-315u.c83
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c99
-rw-r--r--drivers/media/rc/keymaps/rc-leadtek-y04g0051.c99
-rw-r--r--drivers/media/rc/keymaps/rc-lirc.c41
-rw-r--r--drivers/media/rc/keymaps/rc-lme2510.c68
-rw-r--r--drivers/media/rc/keymaps/rc-manli.c134
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-ii.c67
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-iii.c85
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c123
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere.c69
-rw-r--r--drivers/media/rc/keymaps/rc-nebula.c96
-rw-r--r--drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c105
-rw-r--r--drivers/media/rc/keymaps/rc-norwood.c85
-rw-r--r--drivers/media/rc/keymaps/rc-npgtech.c80
-rw-r--r--drivers/media/rc/keymaps/rc-pctv-sedna.c80
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-color.c94
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-grey.c89
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c73
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-002t.c77
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-mk12.c83
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-new.c83
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview.c82
-rw-r--r--drivers/media/rc/keymaps/rc-powercolor-real-angel.c81
-rw-r--r--drivers/media/rc/keymaps/rc-proteus-2309.c69
-rw-r--r--drivers/media/rc/keymaps/rc-purpletv.c81
-rw-r--r--drivers/media/rc/keymaps/rc-pv951.c78
-rw-r--r--drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c141
-rw-r--r--drivers/media/rc/keymaps/rc-rc5-tv.c81
-rw-r--r--drivers/media/rc/keymaps/rc-rc6-mce.c113
-rw-r--r--drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c78
-rw-r--r--drivers/media/rc/keymaps/rc-streamzap.c82
-rw-r--r--drivers/media/rc/keymaps/rc-tbs-nec.c75
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c92
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-slim.c79
-rw-r--r--drivers/media/rc/keymaps/rc-tevii-nec.c88
-rw-r--r--drivers/media/rc/keymaps/rc-total-media-in-hand.c85
-rw-r--r--drivers/media/rc/keymaps/rc-trekstor.c80
-rw-r--r--drivers/media/rc/keymaps/rc-tt-1500.c82
-rw-r--r--drivers/media/rc/keymaps/rc-twinhan1027.c87
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-m1f.c92
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-s350.c85
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-tv-pvr.c87
-rw-r--r--drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c82
-rw-r--r--drivers/media/rc/keymaps/rc-winfast.c102
-rw-r--r--drivers/media/rc/lirc_dev.c816
-rw-r--r--drivers/media/rc/mceusb.c1313
-rw-r--r--drivers/media/rc/nuvoton-cir.c1244
-rw-r--r--drivers/media/rc/nuvoton-cir.h407
-rw-r--r--drivers/media/rc/rc-core-priv.h193
-rw-r--r--drivers/media/rc/rc-loopback.c260
-rw-r--r--drivers/media/rc/rc-main.c1135
-rw-r--r--drivers/media/rc/streamzap.c557
-rw-r--r--drivers/media/rc/winbond-cir.c932
112 files changed, 21108 insertions, 0 deletions
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
new file mode 100644
index 000000000000..3785162f928e
--- /dev/null
+++ b/drivers/media/rc/Kconfig
@@ -0,0 +1,193 @@
1menuconfig RC_CORE
2 tristate "Remote Controller adapters"
3 depends on INPUT
4 default INPUT
5 ---help---
6 Enable support for Remote Controllers on Linux. This is
7 needed in order to support several video capture adapters.
8 Currently, all supported devices use InfraRed.
9
10 Enable this option if you have a video capture board even
11 if you don't need IR, as otherwise, you may not be able to
12 compile the driver for your adapter.
13
14if RC_CORE
15
16config LIRC
17 tristate
18 default y
19
20 ---help---
21 Enable this option to build the Linux Infrared Remote
22 Control (LIRC) core device interface driver. The LIRC
23 interface passes raw IR to and from userspace, where the
24 LIRC daemon handles protocol decoding for IR reception and
25 encoding for IR transmitting (aka "blasting").
26
27source "drivers/media/rc/keymaps/Kconfig"
28
29config IR_NEC_DECODER
30 tristate "Enable IR raw decoder for the NEC protocol"
31 depends on RC_CORE
32 select BITREVERSE
33 default y
34
35 ---help---
36 Enable this option if you have IR with NEC protocol, and
37 if the IR is decoded in software
38
39config IR_RC5_DECODER
40 tristate "Enable IR raw decoder for the RC-5 protocol"
41 depends on RC_CORE
42 select BITREVERSE
43 default y
44
45 ---help---
46 Enable this option if you have IR with RC-5 protocol, and
47 if the IR is decoded in software
48
49config IR_RC6_DECODER
50 tristate "Enable IR raw decoder for the RC6 protocol"
51 depends on RC_CORE
52 select BITREVERSE
53 default y
54
55 ---help---
56 Enable this option if you have an infrared remote control which
57 uses the RC6 protocol, and you need software decoding support.
58
59config IR_JVC_DECODER
60 tristate "Enable IR raw decoder for the JVC protocol"
61 depends on RC_CORE
62 select BITREVERSE
63 default y
64
65 ---help---
66 Enable this option if you have an infrared remote control which
67 uses the JVC protocol, and you need software decoding support.
68
69config IR_SONY_DECODER
70 tristate "Enable IR raw decoder for the Sony protocol"
71 depends on RC_CORE
72 default y
73
74 ---help---
75 Enable this option if you have an infrared remote control which
76 uses the Sony protocol, and you need software decoding support.
77
78config IR_RC5_SZ_DECODER
79 tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
80 depends on RC_CORE
81 select BITREVERSE
82 default y
83
84 ---help---
85 Enable this option if you have IR with RC-5 (streamzap) protocol,
86 and if the IR is decoded in software. (The Streamzap PC Remote
87 uses an IR protocol that is almost standard RC-5, but not quite,
88 as it uses an additional bit).
89
90config IR_LIRC_CODEC
91 tristate "Enable IR to LIRC bridge"
92 depends on RC_CORE
93 depends on LIRC
94 default y
95
96 ---help---
97 Enable this option to pass raw IR to and from userspace via
98 the LIRC interface.
99
100config IR_ENE
101 tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
102 depends on PNP
103 depends on RC_CORE
104 ---help---
105 Say Y here to enable support for integrated infrared receiver
106 /transceiver made by ENE.
107
108 You can see if you have it by looking at lspnp output.
109 Output should include ENE0100 ENE0200 or something similar.
110
111 To compile this driver as a module, choose M here: the
112 module will be called ene_ir.
113
114config IR_IMON
115 tristate "SoundGraph iMON Receiver and Display"
116 depends on USB_ARCH_HAS_HCD
117 depends on RC_CORE
118 select USB
119 ---help---
120 Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
121 IR Receiver and/or LCD/VFD/VGA display.
122
123 To compile this driver as a module, choose M here: the
124 module will be called imon.
125
126config IR_MCEUSB
127 tristate "Windows Media Center Ed. eHome Infrared Transceiver"
128 depends on USB_ARCH_HAS_HCD
129 depends on RC_CORE
130 select USB
131 ---help---
132 Say Y here if you want to use a Windows Media Center Edition
133 eHome Infrared Transceiver.
134
135 To compile this driver as a module, choose M here: the
136 module will be called mceusb.
137
138config IR_NUVOTON
139 tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
140 depends on PNP
141 depends on RC_CORE
142 ---help---
143 Say Y here to enable support for integrated infrared receiver
144 /transciever made by Nuvoton (formerly Winbond). This chip is
145 found in the ASRock ION 330HT, as well as assorted Intel
146 DP55-series motherboards (and of course, possibly others).
147
148 To compile this driver as a module, choose M here: the
149 module will be called nuvoton-cir.
150
151config IR_STREAMZAP
152 tristate "Streamzap PC Remote IR Receiver"
153 depends on USB_ARCH_HAS_HCD
154 depends on RC_CORE
155 select USB
156 ---help---
157 Say Y here if you want to use a Streamzap PC Remote
158 Infrared Receiver.
159
160 To compile this driver as a module, choose M here: the
161 module will be called streamzap.
162
163config IR_WINBOND_CIR
164 tristate "Winbond IR remote control"
165 depends on X86 && PNP
166 depends on RC_CORE
167 select NEW_LEDS
168 select LEDS_CLASS
169 select LEDS_TRIGGERS
170 select BITREVERSE
171 ---help---
172 Say Y here if you want to use the IR remote functionality found
173 in some Winbond SuperI/O chips. Currently only the WPCD376I
174 chip is supported (included in some Intel Media series
175 motherboards).
176
177 To compile this driver as a module, choose M here: the module will
178 be called winbond_cir.
179
180config RC_LOOPBACK
181 tristate "Remote Control Loopback Driver"
182 depends on RC_CORE
183 ---help---
184 Say Y here if you want support for the remote control loopback
185 driver which allows TX data to be sent back as RX data.
186 This is mostly useful for debugging purposes.
187
188 If you're not sure, select N here.
189
190 To compile this driver as a module, choose M here: the module will
191 be called rc_loopback.
192
193endif #RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
new file mode 100644
index 000000000000..67b4f7fe2577
--- /dev/null
+++ b/drivers/media/rc/Makefile
@@ -0,0 +1,22 @@
1rc-core-objs := rc-main.o ir-raw.o
2
3obj-y += keymaps/
4
5obj-$(CONFIG_RC_CORE) += rc-core.o
6obj-$(CONFIG_LIRC) += lirc_dev.o
7obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
8obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
9obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
10obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
11obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
12obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
13obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
14
15# stand-alone IR receivers/transmitters
16obj-$(CONFIG_IR_IMON) += imon.o
17obj-$(CONFIG_IR_MCEUSB) += mceusb.o
18obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
19obj-$(CONFIG_IR_ENE) += ene_ir.o
20obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
21obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
22obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
new file mode 100644
index 000000000000..80b3c319f698
--- /dev/null
+++ b/drivers/media/rc/ene_ir.c
@@ -0,0 +1,1208 @@
1/*
2 * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX)
3 *
4 * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 *
21 * Special thanks to:
22 * Sami R. <maesesami@gmail.com> for lot of help in debugging and therefore
23 * bringing to life support for transmission & learning mode.
24 *
25 * Charlie Andrews <charliethepilot@googlemail.com> for lots of help in
26 * bringing up the support of new firmware buffer that is popular
27 * on latest notebooks
28 *
29 * ENE for partial device documentation
30 *
31 */
32
33#include <linux/kernel.h>
34#include <linux/module.h>
35#include <linux/pnp.h>
36#include <linux/io.h>
37#include <linux/interrupt.h>
38#include <linux/sched.h>
39#include <linux/slab.h>
40#include <media/rc-core.h>
41#include "ene_ir.h"
42
43static int sample_period;
44static bool learning_mode_force;
45static int debug;
46static bool txsim;
47
48static void ene_set_reg_addr(struct ene_device *dev, u16 reg)
49{
50 outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
51 outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
52}
53
54/* read a hardware register */
55static u8 ene_read_reg(struct ene_device *dev, u16 reg)
56{
57 u8 retval;
58 ene_set_reg_addr(dev, reg);
59 retval = inb(dev->hw_io + ENE_IO);
60 dbg_regs("reg %04x == %02x", reg, retval);
61 return retval;
62}
63
64/* write a hardware register */
65static void ene_write_reg(struct ene_device *dev, u16 reg, u8 value)
66{
67 dbg_regs("reg %04x <- %02x", reg, value);
68 ene_set_reg_addr(dev, reg);
69 outb(value, dev->hw_io + ENE_IO);
70}
71
72/* Set bits in hardware register */
73static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
74{
75 dbg_regs("reg %04x |= %02x", reg, mask);
76 ene_set_reg_addr(dev, reg);
77 outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO);
78}
79
80/* Clear bits in hardware register */
81static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
82{
83 dbg_regs("reg %04x &= ~%02x ", reg, mask);
84 ene_set_reg_addr(dev, reg);
85 outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO);
86}
87
88/* A helper to set/clear a bit in register according to boolean variable */
89static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask,
90 bool set)
91{
92 if (set)
93 ene_set_reg_mask(dev, reg, mask);
94 else
95 ene_clear_reg_mask(dev, reg, mask);
96}
97
98/* detect hardware features */
99static int ene_hw_detect(struct ene_device *dev)
100{
101 u8 chip_major, chip_minor;
102 u8 hw_revision, old_ver;
103 u8 fw_reg2, fw_reg1;
104
105 ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
106 chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR);
107 chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR);
108 ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
109
110 hw_revision = ene_read_reg(dev, ENE_ECHV);
111 old_ver = ene_read_reg(dev, ENE_HW_VER_OLD);
112
113 dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) +
114 (ene_read_reg(dev, ENE_PLLFRL) >> 4);
115
116 if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD)
117 dev->rx_period_adjust =
118 dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4;
119
120 if (hw_revision == 0xFF) {
121 ene_warn("device seems to be disabled");
122 ene_warn("send a mail to lirc-list@lists.sourceforge.net");
123 ene_warn("please attach output of acpidump and dmidecode");
124 return -ENODEV;
125 }
126
127 ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x",
128 chip_major, chip_minor, old_ver, hw_revision);
129
130 ene_notice("PLL freq = %d", dev->pll_freq);
131
132 if (chip_major == 0x33) {
133 ene_warn("chips 0x33xx aren't supported");
134 return -ENODEV;
135 }
136
137 if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
138 dev->hw_revision = ENE_HW_C;
139 ene_notice("KB3926C detected");
140 } else if (old_ver == 0x24 && hw_revision == 0xC0) {
141 dev->hw_revision = ENE_HW_B;
142 ene_notice("KB3926B detected");
143 } else {
144 dev->hw_revision = ENE_HW_D;
145 ene_notice("KB3926D or higher detected");
146 }
147
148 /* detect features hardware supports */
149 if (dev->hw_revision < ENE_HW_C)
150 return 0;
151
152 fw_reg1 = ene_read_reg(dev, ENE_FW1);
153 fw_reg2 = ene_read_reg(dev, ENE_FW2);
154
155 ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2);
156
157 dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A);
158 dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING);
159 dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF);
160
161 if (dev->hw_learning_and_tx_capable)
162 dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT);
163
164 ene_notice("Hardware features:");
165
166 if (dev->hw_learning_and_tx_capable) {
167 ene_notice("* Supports transmitting & learning mode");
168 ene_notice(" This feature is rare and therefore,");
169 ene_notice(" you are welcome to test it,");
170 ene_notice(" and/or contact the author via:");
171 ene_notice(" lirc-list@lists.sourceforge.net");
172 ene_notice(" or maximlevitsky@gmail.com");
173
174 ene_notice("* Uses GPIO %s for IR raw input",
175 dev->hw_use_gpio_0a ? "40" : "0A");
176
177 if (dev->hw_fan_input)
178 ene_notice("* Uses unused fan feedback input as source"
179 " of demodulated IR data");
180 }
181
182 if (!dev->hw_fan_input)
183 ene_notice("* Uses GPIO %s for IR demodulated input",
184 dev->hw_use_gpio_0a ? "0A" : "40");
185
186 if (dev->hw_extra_buffer)
187 ene_notice("* Uses new style input buffer");
188 return 0;
189}
190
191/* Read properities of hw sample buffer */
192static void ene_rx_setup_hw_buffer(struct ene_device *dev)
193{
194 u16 tmp;
195
196 ene_rx_read_hw_pointer(dev);
197 dev->r_pointer = dev->w_pointer;
198
199 if (!dev->hw_extra_buffer) {
200 dev->buffer_len = ENE_FW_PACKET_SIZE * 2;
201 return;
202 }
203
204 tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER);
205 tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8;
206 dev->extra_buf1_address = tmp;
207
208 dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2);
209
210 tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3);
211 tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8;
212 dev->extra_buf2_address = tmp;
213
214 dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5);
215
216 dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8;
217
218 ene_notice("Hardware uses 2 extended buffers:");
219 ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address,
220 dev->extra_buf1_len);
221 ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address,
222 dev->extra_buf2_len);
223
224 ene_notice("Total buffer len = %d", dev->buffer_len);
225
226 if (dev->buffer_len > 64 || dev->buffer_len < 16)
227 goto error;
228
229 if (dev->extra_buf1_address > 0xFBFC ||
230 dev->extra_buf1_address < 0xEC00)
231 goto error;
232
233 if (dev->extra_buf2_address > 0xFBFC ||
234 dev->extra_buf2_address < 0xEC00)
235 goto error;
236
237 if (dev->r_pointer > dev->buffer_len)
238 goto error;
239
240 ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
241 return;
242error:
243 ene_warn("Error validating extra buffers, device probably won't work");
244 dev->hw_extra_buffer = false;
245 ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
246}
247
248
249/* Restore the pointers to extra buffers - to make module reload work*/
250static void ene_rx_restore_hw_buffer(struct ene_device *dev)
251{
252 if (!dev->hw_extra_buffer)
253 return;
254
255 ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0,
256 dev->extra_buf1_address & 0xFF);
257 ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1,
258 dev->extra_buf1_address >> 8);
259 ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len);
260
261 ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3,
262 dev->extra_buf2_address & 0xFF);
263 ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4,
264 dev->extra_buf2_address >> 8);
265 ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5,
266 dev->extra_buf2_len);
267 ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
268}
269
270/* Read hardware write pointer */
271static void ene_rx_read_hw_pointer(struct ene_device *dev)
272{
273 if (dev->hw_extra_buffer)
274 dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER);
275 else
276 dev->w_pointer = ene_read_reg(dev, ENE_FW2)
277 & ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE;
278
279 dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x",
280 dev->w_pointer, dev->r_pointer);
281}
282
283/* Gets address of next sample from HW ring buffer */
284static int ene_rx_get_sample_reg(struct ene_device *dev)
285{
286 int r_pointer;
287
288 if (dev->r_pointer == dev->w_pointer) {
289 dbg_verbose("RB: hit end, try update w_pointer");
290 ene_rx_read_hw_pointer(dev);
291 }
292
293 if (dev->r_pointer == dev->w_pointer) {
294 dbg_verbose("RB: end of data at %d", dev->r_pointer);
295 return 0;
296 }
297
298 dbg_verbose("RB: reading at offset %d", dev->r_pointer);
299 r_pointer = dev->r_pointer;
300
301 dev->r_pointer++;
302 if (dev->r_pointer == dev->buffer_len)
303 dev->r_pointer = 0;
304
305 dbg_verbose("RB: next read will be from offset %d", dev->r_pointer);
306
307 if (r_pointer < 8) {
308 dbg_verbose("RB: read at main buffer at %d", r_pointer);
309 return ENE_FW_SAMPLE_BUFFER + r_pointer;
310 }
311
312 r_pointer -= 8;
313
314 if (r_pointer < dev->extra_buf1_len) {
315 dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer);
316 return dev->extra_buf1_address + r_pointer;
317 }
318
319 r_pointer -= dev->extra_buf1_len;
320
321 if (r_pointer < dev->extra_buf2_len) {
322 dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer);
323 return dev->extra_buf2_address + r_pointer;
324 }
325
326 dbg("attempt to read beyong ring bufer end");
327 return 0;
328}
329
330/* Sense current received carrier */
331void ene_rx_sense_carrier(struct ene_device *dev)
332{
333 DEFINE_IR_RAW_EVENT(ev);
334
335 int carrier, duty_cycle;
336 int period = ene_read_reg(dev, ENE_CIRCAR_PRD);
337 int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD);
338
339 if (!(period & ENE_CIRCAR_PRD_VALID))
340 return;
341
342 period &= ~ENE_CIRCAR_PRD_VALID;
343
344 if (!period)
345 return;
346
347 dbg("RX: hardware carrier period = %02x", period);
348 dbg("RX: hardware carrier pulse period = %02x", hperiod);
349
350 carrier = 2000000 / period;
351 duty_cycle = (hperiod * 100) / period;
352 dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
353 carrier, duty_cycle);
354 if (dev->carrier_detect_enabled) {
355 ev.carrier_report = true;
356 ev.carrier = carrier;
357 ev.duty_cycle = duty_cycle;
358 ir_raw_event_store(dev->rdev, &ev);
359 }
360}
361
362/* this enables/disables the CIR RX engine */
363static void ene_rx_enable_cir_engine(struct ene_device *dev, bool enable)
364{
365 ene_set_clear_reg_mask(dev, ENE_CIRCFG,
366 ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable);
367}
368
369/* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/
370static void ene_rx_select_input(struct ene_device *dev, bool gpio_0a)
371{
372 ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a);
373}
374
375/*
376 * this enables alternative input via fan tachometer sensor and bypasses
377 * the hw CIR engine
378 */
379static void ene_rx_enable_fan_input(struct ene_device *dev, bool enable)
380{
381 if (!dev->hw_fan_input)
382 return;
383
384 if (!enable)
385 ene_write_reg(dev, ENE_FAN_AS_IN1, 0);
386 else {
387 ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
388 ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
389 }
390}
391
392/* setup the receiver for RX*/
393static void ene_rx_setup(struct ene_device *dev)
394{
395 bool learning_mode = dev->learning_mode_enabled ||
396 dev->carrier_detect_enabled;
397 int sample_period_adjust = 0;
398
399 dbg("RX: setup receiver, learning mode = %d", learning_mode);
400
401
402 /* This selects RLC input and clears CFG2 settings */
403 ene_write_reg(dev, ENE_CIRCFG2, 0x00);
404
405 /* set sample period*/
406 if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD)
407 sample_period_adjust =
408 dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2;
409
410 ene_write_reg(dev, ENE_CIRRLC_CFG,
411 (sample_period + sample_period_adjust) |
412 ENE_CIRRLC_CFG_OVERFLOW);
413 /* revB doesn't support inputs */
414 if (dev->hw_revision < ENE_HW_C)
415 goto select_timeout;
416
417 if (learning_mode) {
418
419 WARN_ON(!dev->hw_learning_and_tx_capable);
420
421 /* Enable the opposite of the normal input
422 That means that if GPIO40 is normally used, use GPIO0A
423 and vice versa.
424 This input will carry non demodulated
425 signal, and we will tell the hw to demodulate it itself */
426 ene_rx_select_input(dev, !dev->hw_use_gpio_0a);
427 dev->rx_fan_input_inuse = false;
428
429 /* Enable carrier demodulation */
430 ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
431
432 /* Enable carrier detection */
433 ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63);
434 ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT,
435 dev->carrier_detect_enabled || debug);
436 } else {
437 if (dev->hw_fan_input)
438 dev->rx_fan_input_inuse = true;
439 else
440 ene_rx_select_input(dev, dev->hw_use_gpio_0a);
441
442 /* Disable carrier detection & demodulation */
443 ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
444 ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT);
445 }
446
447select_timeout:
448 if (dev->rx_fan_input_inuse) {
449 dev->rdev->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
450
451 /* Fan input doesn't support timeouts, it just ends the
452 input with a maximum sample */
453 dev->rdev->min_timeout = dev->rdev->max_timeout =
454 MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
455 ENE_FW_SAMPLE_PERIOD_FAN);
456 } else {
457 dev->rdev->rx_resolution = MS_TO_NS(sample_period);
458
459 /* Theoreticly timeout is unlimited, but we cap it
460 * because it was seen that on one device, it
461 * would stop sending spaces after around 250 msec.
462 * Besides, this is close to 2^32 anyway and timeout is u32.
463 */
464 dev->rdev->min_timeout = MS_TO_NS(127 * sample_period);
465 dev->rdev->max_timeout = MS_TO_NS(200000);
466 }
467
468 if (dev->hw_learning_and_tx_capable)
469 dev->rdev->tx_resolution = MS_TO_NS(sample_period);
470
471 if (dev->rdev->timeout > dev->rdev->max_timeout)
472 dev->rdev->timeout = dev->rdev->max_timeout;
473 if (dev->rdev->timeout < dev->rdev->min_timeout)
474 dev->rdev->timeout = dev->rdev->min_timeout;
475}
476
477/* Enable the device for receive */
478static void ene_rx_enable(struct ene_device *dev)
479{
480 u8 reg_value;
481
482 /* Enable system interrupt */
483 if (dev->hw_revision < ENE_HW_C) {
484 ene_write_reg(dev, ENEB_IRQ, dev->irq << 1);
485 ene_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
486 } else {
487 reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0;
488 reg_value |= ENE_IRQ_UNK_EN;
489 reg_value &= ~ENE_IRQ_STATUS;
490 reg_value |= (dev->irq & ENE_IRQ_MASK);
491 ene_write_reg(dev, ENE_IRQ, reg_value);
492 }
493
494 /* Enable inputs */
495 ene_rx_enable_fan_input(dev, dev->rx_fan_input_inuse);
496 ene_rx_enable_cir_engine(dev, !dev->rx_fan_input_inuse);
497
498 /* ack any pending irqs - just in case */
499 ene_irq_status(dev);
500
501 /* enable firmware bits */
502 ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
503
504 /* enter idle mode */
505 ir_raw_event_set_idle(dev->rdev, true);
506 dev->rx_enabled = true;
507}
508
509/* Disable the device receiver */
510static void ene_rx_disable(struct ene_device *dev)
511{
512 /* disable inputs */
513 ene_rx_enable_cir_engine(dev, false);
514 ene_rx_enable_fan_input(dev, false);
515
516 /* disable hardware IRQ and firmware flag */
517 ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
518
519 ir_raw_event_set_idle(dev->rdev, true);
520 dev->rx_enabled = false;
521}
522
523/* This resets the receiver. Usefull to stop stream of spaces at end of
524 * transmission
525 */
526static void ene_rx_reset(struct ene_device *dev)
527{
528 ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
529 ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
530}
531
532/* Set up the TX carrier frequency and duty cycle */
533static void ene_tx_set_carrier(struct ene_device *dev)
534{
535 u8 tx_puls_width;
536 unsigned long flags;
537
538 spin_lock_irqsave(&dev->hw_lock, flags);
539
540 ene_set_clear_reg_mask(dev, ENE_CIRCFG,
541 ENE_CIRCFG_TX_CARR, dev->tx_period > 0);
542
543 if (!dev->tx_period)
544 goto unlock;
545
546 BUG_ON(dev->tx_duty_cycle >= 100 || dev->tx_duty_cycle <= 0);
547
548 tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle);
549
550 if (!tx_puls_width)
551 tx_puls_width = 1;
552
553 dbg("TX: pulse distance = %d * 500 ns", dev->tx_period);
554 dbg("TX: pulse width = %d * 500 ns", tx_puls_width);
555
556 ene_write_reg(dev, ENE_CIRMOD_PRD, dev->tx_period | ENE_CIRMOD_PRD_POL);
557 ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width);
558unlock:
559 spin_unlock_irqrestore(&dev->hw_lock, flags);
560}
561
562/* Enable/disable transmitters */
563static void ene_tx_set_transmitters(struct ene_device *dev)
564{
565 unsigned long flags;
566
567 spin_lock_irqsave(&dev->hw_lock, flags);
568 ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41,
569 !!(dev->transmitter_mask & 0x01));
570 ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D,
571 !!(dev->transmitter_mask & 0x02));
572 spin_unlock_irqrestore(&dev->hw_lock, flags);
573}
574
575/* prepare transmission */
576static void ene_tx_enable(struct ene_device *dev)
577{
578 u8 conf1 = ene_read_reg(dev, ENE_CIRCFG);
579 u8 fwreg2 = ene_read_reg(dev, ENE_FW2);
580
581 dev->saved_conf1 = conf1;
582
583 /* Show information about currently connected transmitter jacks */
584 if (fwreg2 & ENE_FW2_EMMITER1_CONN)
585 dbg("TX: Transmitter #1 is connected");
586
587 if (fwreg2 & ENE_FW2_EMMITER2_CONN)
588 dbg("TX: Transmitter #2 is connected");
589
590 if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN)))
591 ene_warn("TX: transmitter cable isn't connected!");
592
593 /* disable receive on revc */
594 if (dev->hw_revision == ENE_HW_C)
595 conf1 &= ~ENE_CIRCFG_RX_EN;
596
597 /* Enable TX engine */
598 conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ;
599 ene_write_reg(dev, ENE_CIRCFG, conf1);
600}
601
602/* end transmission */
603static void ene_tx_disable(struct ene_device *dev)
604{
605 ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
606 dev->tx_buffer = NULL;
607}
608
609
610/* TX one sample - must be called with dev->hw_lock*/
611static void ene_tx_sample(struct ene_device *dev)
612{
613 u8 raw_tx;
614 u32 sample;
615 bool pulse = dev->tx_sample_pulse;
616
617 if (!dev->tx_buffer) {
618 ene_warn("TX: BUG: attempt to transmit NULL buffer");
619 return;
620 }
621
622 /* Grab next TX sample */
623 if (!dev->tx_sample) {
624
625 if (dev->tx_pos == dev->tx_len) {
626 if (!dev->tx_done) {
627 dbg("TX: no more data to send");
628 dev->tx_done = true;
629 goto exit;
630 } else {
631 dbg("TX: last sample sent by hardware");
632 ene_tx_disable(dev);
633 complete(&dev->tx_complete);
634 return;
635 }
636 }
637
638 sample = dev->tx_buffer[dev->tx_pos++];
639 dev->tx_sample_pulse = !dev->tx_sample_pulse;
640
641 dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);
642
643 if (!dev->tx_sample)
644 dev->tx_sample = 1;
645 }
646
647 raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
648 dev->tx_sample -= raw_tx;
649
650 dbg("TX: sample %8d (%s)", raw_tx * sample_period,
651 pulse ? "pulse" : "space");
652 if (pulse)
653 raw_tx |= ENE_CIRRLC_OUT_PULSE;
654
655 ene_write_reg(dev,
656 dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);
657
658 dev->tx_reg = !dev->tx_reg;
659exit:
660 /* simulate TX done interrupt */
661 if (txsim)
662 mod_timer(&dev->tx_sim_timer, jiffies + HZ / 500);
663}
664
665/* timer to simulate tx done interrupt */
666static void ene_tx_irqsim(unsigned long data)
667{
668 struct ene_device *dev = (struct ene_device *)data;
669 unsigned long flags;
670
671 spin_lock_irqsave(&dev->hw_lock, flags);
672 ene_tx_sample(dev);
673 spin_unlock_irqrestore(&dev->hw_lock, flags);
674}
675
676
677/* read irq status and ack it */
678static int ene_irq_status(struct ene_device *dev)
679{
680 u8 irq_status;
681 u8 fw_flags1, fw_flags2;
682 int retval = 0;
683
684 fw_flags2 = ene_read_reg(dev, ENE_FW2);
685
686 if (dev->hw_revision < ENE_HW_C) {
687 irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS);
688
689 if (!(irq_status & ENEB_IRQ_STATUS_IR))
690 return 0;
691
692 ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR);
693 return ENE_IRQ_RX;
694 }
695
696 irq_status = ene_read_reg(dev, ENE_IRQ);
697 if (!(irq_status & ENE_IRQ_STATUS))
698 return 0;
699
700 /* original driver does that twice - a workaround ? */
701 ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
702 ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
703
704 /* check RX interrupt */
705 if (fw_flags2 & ENE_FW2_RXIRQ) {
706 retval |= ENE_IRQ_RX;
707 ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ);
708 }
709
710 /* check TX interrupt */
711 fw_flags1 = ene_read_reg(dev, ENE_FW1);
712 if (fw_flags1 & ENE_FW1_TXIRQ) {
713 ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
714 retval |= ENE_IRQ_TX;
715 }
716
717 return retval;
718}
719
720/* interrupt handler */
721static irqreturn_t ene_isr(int irq, void *data)
722{
723 u16 hw_value, reg;
724 int hw_sample, irq_status;
725 bool pulse;
726 unsigned long flags;
727 irqreturn_t retval = IRQ_NONE;
728 struct ene_device *dev = (struct ene_device *)data;
729 DEFINE_IR_RAW_EVENT(ev);
730
731 spin_lock_irqsave(&dev->hw_lock, flags);
732
733 dbg_verbose("ISR called");
734 ene_rx_read_hw_pointer(dev);
735 irq_status = ene_irq_status(dev);
736
737 if (!irq_status)
738 goto unlock;
739
740 retval = IRQ_HANDLED;
741
742 if (irq_status & ENE_IRQ_TX) {
743 dbg_verbose("TX interrupt");
744 if (!dev->hw_learning_and_tx_capable) {
745 dbg("TX interrupt on unsupported device!");
746 goto unlock;
747 }
748 ene_tx_sample(dev);
749 }
750
751 if (!(irq_status & ENE_IRQ_RX))
752 goto unlock;
753
754 dbg_verbose("RX interrupt");
755
756 if (dev->hw_learning_and_tx_capable)
757 ene_rx_sense_carrier(dev);
758
759 /* On hardware that don't support extra buffer we need to trust
760 the interrupt and not track the read pointer */
761 if (!dev->hw_extra_buffer)
762 dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0;
763
764 while (1) {
765
766 reg = ene_rx_get_sample_reg(dev);
767
768 dbg_verbose("next sample to read at: %04x", reg);
769 if (!reg)
770 break;
771
772 hw_value = ene_read_reg(dev, reg);
773
774 if (dev->rx_fan_input_inuse) {
775
776 int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER;
777
778 /* read high part of the sample */
779 hw_value |= ene_read_reg(dev, reg + offset) << 8;
780 pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS;
781
782 /* clear space bit, and other unused bits */
783 hw_value &= ENE_FW_SMPL_BUF_FAN_MSK;
784 hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN;
785
786 } else {
787 pulse = !(hw_value & ENE_FW_SAMPLE_SPACE);
788 hw_value &= ~ENE_FW_SAMPLE_SPACE;
789 hw_sample = hw_value * sample_period;
790
791 if (dev->rx_period_adjust) {
792 hw_sample *= 100;
793 hw_sample /= (100 + dev->rx_period_adjust);
794 }
795 }
796
797 if (!dev->hw_extra_buffer && !hw_sample) {
798 dev->r_pointer = dev->w_pointer;
799 continue;
800 }
801
802 dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
803
804 ev.duration = MS_TO_NS(hw_sample);
805 ev.pulse = pulse;
806 ir_raw_event_store_with_filter(dev->rdev, &ev);
807 }
808
809 ir_raw_event_handle(dev->rdev);
810unlock:
811 spin_unlock_irqrestore(&dev->hw_lock, flags);
812 return retval;
813}
814
815/* Initialize default settings */
816static void ene_setup_default_settings(struct ene_device *dev)
817{
818 dev->tx_period = 32;
819 dev->tx_duty_cycle = 50; /*%*/
820 dev->transmitter_mask = 0x03;
821 dev->learning_mode_enabled = learning_mode_force;
822
823 /* Set reasonable default timeout */
824 dev->rdev->timeout = MS_TO_NS(150000);
825}
826
827/* Upload all hardware settings at once. Used at load and resume time */
828static void ene_setup_hw_settings(struct ene_device *dev)
829{
830 if (dev->hw_learning_and_tx_capable) {
831 ene_tx_set_carrier(dev);
832 ene_tx_set_transmitters(dev);
833 }
834
835 ene_rx_setup(dev);
836}
837
838/* outside interface: called on first open*/
839static int ene_open(struct rc_dev *rdev)
840{
841 struct ene_device *dev = rdev->priv;
842 unsigned long flags;
843
844 spin_lock_irqsave(&dev->hw_lock, flags);
845 ene_rx_enable(dev);
846 spin_unlock_irqrestore(&dev->hw_lock, flags);
847 return 0;
848}
849
850/* outside interface: called on device close*/
851static void ene_close(struct rc_dev *rdev)
852{
853 struct ene_device *dev = rdev->priv;
854 unsigned long flags;
855 spin_lock_irqsave(&dev->hw_lock, flags);
856
857 ene_rx_disable(dev);
858 spin_unlock_irqrestore(&dev->hw_lock, flags);
859}
860
861/* outside interface: set transmitter mask */
862static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask)
863{
864 struct ene_device *dev = rdev->priv;
865 dbg("TX: attempt to set transmitter mask %02x", tx_mask);
866
867 /* invalid txmask */
868 if (!tx_mask || tx_mask & ~0x03) {
869 dbg("TX: invalid mask");
870 /* return count of transmitters */
871 return 2;
872 }
873
874 dev->transmitter_mask = tx_mask;
875 ene_tx_set_transmitters(dev);
876 return 0;
877}
878
879/* outside interface : set tx carrier */
880static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier)
881{
882 struct ene_device *dev = rdev->priv;
883 u32 period = 2000000 / carrier;
884
885 dbg("TX: attempt to set tx carrier to %d kHz", carrier);
886
887 if (period && (period > ENE_CIRMOD_PRD_MAX ||
888 period < ENE_CIRMOD_PRD_MIN)) {
889
890 dbg("TX: out of range %d-%d kHz carrier",
891 2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX);
892 return -1;
893 }
894
895 dev->tx_period = period;
896 ene_tx_set_carrier(dev);
897 return 0;
898}
899
900/*outside interface : set tx duty cycle */
901static int ene_set_tx_duty_cycle(struct rc_dev *rdev, u32 duty_cycle)
902{
903 struct ene_device *dev = rdev->priv;
904 dbg("TX: setting duty cycle to %d%%", duty_cycle);
905 dev->tx_duty_cycle = duty_cycle;
906 ene_tx_set_carrier(dev);
907 return 0;
908}
909
910/* outside interface: enable learning mode */
911static int ene_set_learning_mode(struct rc_dev *rdev, int enable)
912{
913 struct ene_device *dev = rdev->priv;
914 unsigned long flags;
915 if (enable == dev->learning_mode_enabled)
916 return 0;
917
918 spin_lock_irqsave(&dev->hw_lock, flags);
919 dev->learning_mode_enabled = enable;
920 ene_rx_disable(dev);
921 ene_rx_setup(dev);
922 ene_rx_enable(dev);
923 spin_unlock_irqrestore(&dev->hw_lock, flags);
924 return 0;
925}
926
927static int ene_set_carrier_report(struct rc_dev *rdev, int enable)
928{
929 struct ene_device *dev = rdev->priv;
930 unsigned long flags;
931
932 if (enable == dev->carrier_detect_enabled)
933 return 0;
934
935 spin_lock_irqsave(&dev->hw_lock, flags);
936 dev->carrier_detect_enabled = enable;
937 ene_rx_disable(dev);
938 ene_rx_setup(dev);
939 ene_rx_enable(dev);
940 spin_unlock_irqrestore(&dev->hw_lock, flags);
941 return 0;
942}
943
944/* outside interface: enable or disable idle mode */
945static void ene_set_idle(struct rc_dev *rdev, bool idle)
946{
947 struct ene_device *dev = rdev->priv;
948
949 if (idle) {
950 ene_rx_reset(dev);
951 dbg("RX: end of data");
952 }
953}
954
955/* outside interface: transmit */
956static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n)
957{
958 struct ene_device *dev = rdev->priv;
959 unsigned long flags;
960
961 dev->tx_buffer = buf;
962 dev->tx_len = n / sizeof(int);
963 dev->tx_pos = 0;
964 dev->tx_reg = 0;
965 dev->tx_done = 0;
966 dev->tx_sample = 0;
967 dev->tx_sample_pulse = 0;
968
969 dbg("TX: %d samples", dev->tx_len);
970
971 spin_lock_irqsave(&dev->hw_lock, flags);
972
973 ene_tx_enable(dev);
974
975 /* Transmit first two samples */
976 ene_tx_sample(dev);
977 ene_tx_sample(dev);
978
979 spin_unlock_irqrestore(&dev->hw_lock, flags);
980
981 if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) {
982 dbg("TX: timeout");
983 spin_lock_irqsave(&dev->hw_lock, flags);
984 ene_tx_disable(dev);
985 spin_unlock_irqrestore(&dev->hw_lock, flags);
986 } else
987 dbg("TX: done");
988 return n;
989}
990
991/* probe entry */
992static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
993{
994 int error = -ENOMEM;
995 struct rc_dev *rdev;
996 struct ene_device *dev;
997
998 /* allocate memory */
999 dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
1000 rdev = rc_allocate_device();
1001 if (!dev || !rdev)
1002 goto error1;
1003
1004 /* validate resources */
1005 error = -ENODEV;
1006
1007 if (!pnp_port_valid(pnp_dev, 0) ||
1008 pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
1009 goto error;
1010
1011 if (!pnp_irq_valid(pnp_dev, 0))
1012 goto error;
1013
1014 spin_lock_init(&dev->hw_lock);
1015
1016 /* claim the resources */
1017 error = -EBUSY;
1018 dev->hw_io = pnp_port_start(pnp_dev, 0);
1019 if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
1020 dev->hw_io = -1;
1021 dev->irq = -1;
1022 goto error;
1023 }
1024
1025 dev->irq = pnp_irq(pnp_dev, 0);
1026 if (request_irq(dev->irq, ene_isr,
1027 IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) {
1028 dev->irq = -1;
1029 goto error;
1030 }
1031
1032 pnp_set_drvdata(pnp_dev, dev);
1033 dev->pnp_dev = pnp_dev;
1034
1035 /* don't allow too short/long sample periods */
1036 if (sample_period < 5 || sample_period > 0x7F)
1037 sample_period = ENE_DEFAULT_SAMPLE_PERIOD;
1038
1039 /* detect hardware version and features */
1040 error = ene_hw_detect(dev);
1041 if (error)
1042 goto error;
1043
1044 if (!dev->hw_learning_and_tx_capable && txsim) {
1045 dev->hw_learning_and_tx_capable = true;
1046 setup_timer(&dev->tx_sim_timer, ene_tx_irqsim,
1047 (long unsigned int)dev);
1048 ene_warn("Simulation of TX activated");
1049 }
1050
1051 if (!dev->hw_learning_and_tx_capable)
1052 learning_mode_force = false;
1053
1054 rdev->driver_type = RC_DRIVER_IR_RAW;
1055 rdev->allowed_protos = RC_TYPE_ALL;
1056 rdev->priv = dev;
1057 rdev->open = ene_open;
1058 rdev->close = ene_close;
1059 rdev->s_idle = ene_set_idle;
1060 rdev->driver_name = ENE_DRIVER_NAME;
1061 rdev->map_name = RC_MAP_RC6_MCE;
1062 rdev->input_name = "ENE eHome Infrared Remote Receiver";
1063
1064 if (dev->hw_learning_and_tx_capable) {
1065 rdev->s_learning_mode = ene_set_learning_mode;
1066 init_completion(&dev->tx_complete);
1067 rdev->tx_ir = ene_transmit;
1068 rdev->s_tx_mask = ene_set_tx_mask;
1069 rdev->s_tx_carrier = ene_set_tx_carrier;
1070 rdev->s_tx_duty_cycle = ene_set_tx_duty_cycle;
1071 rdev->s_carrier_report = ene_set_carrier_report;
1072 rdev->input_name = "ENE eHome Infrared Remote Transceiver";
1073 }
1074
1075 ene_rx_setup_hw_buffer(dev);
1076 ene_setup_default_settings(dev);
1077 ene_setup_hw_settings(dev);
1078
1079 device_set_wakeup_capable(&pnp_dev->dev, true);
1080 device_set_wakeup_enable(&pnp_dev->dev, true);
1081
1082 error = rc_register_device(rdev);
1083 if (error < 0)
1084 goto error;
1085
1086 dev->rdev = rdev;
1087 ene_notice("driver has been succesfully loaded");
1088 return 0;
1089error:
1090 if (dev && dev->irq >= 0)
1091 free_irq(dev->irq, dev);
1092 if (dev && dev->hw_io >= 0)
1093 release_region(dev->hw_io, ENE_IO_SIZE);
1094error1:
1095 rc_free_device(rdev);
1096 kfree(dev);
1097 return error;
1098}
1099
1100/* main unload function */
1101static void ene_remove(struct pnp_dev *pnp_dev)
1102{
1103 struct ene_device *dev = pnp_get_drvdata(pnp_dev);
1104 unsigned long flags;
1105
1106 spin_lock_irqsave(&dev->hw_lock, flags);
1107 ene_rx_disable(dev);
1108 ene_rx_restore_hw_buffer(dev);
1109 spin_unlock_irqrestore(&dev->hw_lock, flags);
1110
1111 free_irq(dev->irq, dev);
1112 release_region(dev->hw_io, ENE_IO_SIZE);
1113 rc_unregister_device(dev->rdev);
1114 kfree(dev);
1115}
1116
1117/* enable wake on IR (wakes on specific button on original remote) */
1118static void ene_enable_wake(struct ene_device *dev, int enable)
1119{
1120 enable = enable && device_may_wakeup(&dev->pnp_dev->dev);
1121 dbg("wake on IR %s", enable ? "enabled" : "disabled");
1122 ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable);
1123}
1124
1125#ifdef CONFIG_PM
1126static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
1127{
1128 struct ene_device *dev = pnp_get_drvdata(pnp_dev);
1129 ene_enable_wake(dev, true);
1130
1131 /* TODO: add support for wake pattern */
1132 return 0;
1133}
1134
1135static int ene_resume(struct pnp_dev *pnp_dev)
1136{
1137 struct ene_device *dev = pnp_get_drvdata(pnp_dev);
1138 ene_setup_hw_settings(dev);
1139
1140 if (dev->rx_enabled)
1141 ene_rx_enable(dev);
1142
1143 ene_enable_wake(dev, false);
1144 return 0;
1145}
1146#endif
1147
1148static void ene_shutdown(struct pnp_dev *pnp_dev)
1149{
1150 struct ene_device *dev = pnp_get_drvdata(pnp_dev);
1151 ene_enable_wake(dev, true);
1152}
1153
1154static const struct pnp_device_id ene_ids[] = {
1155 {.id = "ENE0100",},
1156 {.id = "ENE0200",},
1157 {.id = "ENE0201",},
1158 {.id = "ENE0202",},
1159 {},
1160};
1161
1162static struct pnp_driver ene_driver = {
1163 .name = ENE_DRIVER_NAME,
1164 .id_table = ene_ids,
1165 .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
1166
1167 .probe = ene_probe,
1168 .remove = __devexit_p(ene_remove),
1169#ifdef CONFIG_PM
1170 .suspend = ene_suspend,
1171 .resume = ene_resume,
1172#endif
1173 .shutdown = ene_shutdown,
1174};
1175
1176static int __init ene_init(void)
1177{
1178 return pnp_register_driver(&ene_driver);
1179}
1180
1181static void ene_exit(void)
1182{
1183 pnp_unregister_driver(&ene_driver);
1184}
1185
1186module_param(sample_period, int, S_IRUGO);
1187MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)");
1188
1189module_param(learning_mode_force, bool, S_IRUGO);
1190MODULE_PARM_DESC(learning_mode_force, "Enable learning mode by default");
1191
1192module_param(debug, int, S_IRUGO | S_IWUSR);
1193MODULE_PARM_DESC(debug, "Debug level");
1194
1195module_param(txsim, bool, S_IRUGO);
1196MODULE_PARM_DESC(txsim,
1197 "Simulate TX features on unsupported hardware (dangerous)");
1198
1199MODULE_DEVICE_TABLE(pnp, ene_ids);
1200MODULE_DESCRIPTION
1201 ("Infrared input driver for KB3926B/C/D/E/F "
1202 "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port");
1203
1204MODULE_AUTHOR("Maxim Levitsky");
1205MODULE_LICENSE("GPL");
1206
1207module_init(ene_init);
1208module_exit(ene_exit);
diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h
new file mode 100644
index 000000000000..c179baf34cb4
--- /dev/null
+++ b/drivers/media/rc/ene_ir.h
@@ -0,0 +1,261 @@
1/*
2 * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX)
3 *
4 * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 * USA
20 */
21#include <linux/spinlock.h>
22
23
24/* hardware address */
25#define ENE_STATUS 0 /* hardware status - unused */
26#define ENE_ADDR_HI 1 /* hi byte of register address */
27#define ENE_ADDR_LO 2 /* low byte of register address */
28#define ENE_IO 3 /* read/write window */
29#define ENE_IO_SIZE 4
30
31/* 8 bytes of samples, divided in 2 packets*/
32#define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */
33#define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */
34#define ENE_FW_PACKET_SIZE 4
35
36/* first firmware flag register */
37#define ENE_FW1 0xF8F8 /* flagr */
38#define ENE_FW1_ENABLE 0x01 /* enable fw processing */
39#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */
40#define ENE_FW1_HAS_EXTRA_BUF 0x04 /* fw uses extra buffer*/
41#define ENE_FW1_EXTRA_BUF_HND 0x08 /* extra buffer handshake bit*/
42#define ENE_FW1_LED_ON 0x10 /* turn on a led */
43
44#define ENE_FW1_WPATTERN 0x20 /* enable wake pattern */
45#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */
46#define ENE_FW1_IRQ 0x80 /* enable interrupt */
47
48/* second firmware flag register */
49#define ENE_FW2 0xF8F9 /* flagw */
50#define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */
51#define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/
52#define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */
53#define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */
54#define ENE_FW2_EMMITER2_CONN 0x20 /* TX emmiter 2 connected */
55
56#define ENE_FW2_FAN_INPUT 0x40 /* fan input used for demodulated data*/
57#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */
58
59/* firmware RX pointer for new style buffer */
60#define ENE_FW_RX_POINTER 0xF8FA
61
62/* high parts of samples for fan input (8 samples)*/
63#define ENE_FW_SMPL_BUF_FAN 0xF8FB
64#define ENE_FW_SMPL_BUF_FAN_PLS 0x8000 /* combined sample is pulse */
65#define ENE_FW_SMPL_BUF_FAN_MSK 0x0FFF /* combined sample maximum value */
66#define ENE_FW_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
67
68/* transmitter ports */
69#define ENE_GPIOFS1 0xFC01
70#define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */
71#define ENE_GPIOFS8 0xFC08
72#define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */
73
74/* IRQ registers block (for revision B) */
75#define ENEB_IRQ 0xFD09 /* IRQ number */
76#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */
77#define ENEB_IRQ_STATUS 0xFD80 /* irq status */
78#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */
79
80/* fan as input settings */
81#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */
82#define ENE_FAN_AS_IN1_EN 0xCD
83#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */
84#define ENE_FAN_AS_IN2_EN 0x03
85
86/* IRQ registers block (for revision C,D) */
87#define ENE_IRQ 0xFE9B /* new irq settings register */
88#define ENE_IRQ_MASK 0x0F /* irq number mask */
89#define ENE_IRQ_UNK_EN 0x10 /* always enabled */
90#define ENE_IRQ_STATUS 0x20 /* irq status and ACK */
91
92/* CIR Config register #1 */
93#define ENE_CIRCFG 0xFEC0
94#define ENE_CIRCFG_RX_EN 0x01 /* RX enable */
95#define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */
96#define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */
97#define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */
98
99#define ENE_CIRCFG_TX_EN 0x10 /* TX enable */
100#define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */
101#define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */
102#define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */
103
104/* CIR config register #2 */
105#define ENE_CIRCFG2 0xFEC1
106#define ENE_CIRCFG2_RLC 0x00
107#define ENE_CIRCFG2_RC5 0x01
108#define ENE_CIRCFG2_RC6 0x02
109#define ENE_CIRCFG2_NEC 0x03
110#define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */
111#define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */
112#define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */
113#define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */
114
115/* Knobs for protocol decoding - will document when/if will use them */
116#define ENE_CIRPF 0xFEC2
117#define ENE_CIRHIGH 0xFEC3
118#define ENE_CIRBIT 0xFEC4
119#define ENE_CIRSTART 0xFEC5
120#define ENE_CIRSTART2 0xFEC6
121
122/* Actual register which contains RLC RX data - read by firmware */
123#define ENE_CIRDAT_IN 0xFEC7
124
125
126/* RLC configuration - sample period (1us resulution) + idle mode */
127#define ENE_CIRRLC_CFG 0xFEC8
128#define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */
129#define ENE_DEFAULT_SAMPLE_PERIOD 50
130
131/* Two byte RLC TX buffer */
132#define ENE_CIRRLC_OUT0 0xFEC9
133#define ENE_CIRRLC_OUT1 0xFECA
134#define ENE_CIRRLC_OUT_PULSE 0x80 /* Transmitted sample is pulse */
135#define ENE_CIRRLC_OUT_MASK 0x7F
136
137
138/* Carrier detect setting
139 * Low nibble - number of carrier pulses to average
140 * High nibble - number of initial carrier pulses to discard
141 */
142#define ENE_CIRCAR_PULS 0xFECB
143
144/* detected RX carrier period (resolution: 500 ns) */
145#define ENE_CIRCAR_PRD 0xFECC
146#define ENE_CIRCAR_PRD_VALID 0x80 /* data valid content valid */
147
148/* detected RX carrier pulse width (resolution: 500 ns) */
149#define ENE_CIRCAR_HPRD 0xFECD
150
151/* TX period (resolution: 500 ns, minimum 2)*/
152#define ENE_CIRMOD_PRD 0xFECE
153#define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/
154
155#define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */
156#define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */
157
158/* TX pulse width (resolution: 500 ns)*/
159#define ENE_CIRMOD_HPRD 0xFECF
160
161/* Hardware versions */
162#define ENE_ECHV 0xFF00 /* hardware revision */
163#define ENE_PLLFRH 0xFF16
164#define ENE_PLLFRL 0xFF17
165#define ENE_DEFAULT_PLL_FREQ 1000
166
167#define ENE_ECSTS 0xFF1D
168#define ENE_ECSTS_RSRVD 0x04
169
170#define ENE_ECVER_MAJOR 0xFF1E /* chip version */
171#define ENE_ECVER_MINOR 0xFF1F
172#define ENE_HW_VER_OLD 0xFD00
173
174/******************************************************************************/
175
176#define ENE_DRIVER_NAME "ene_ir"
177
178#define ENE_IRQ_RX 1
179#define ENE_IRQ_TX 2
180
181#define ENE_HW_B 1 /* 3926B */
182#define ENE_HW_C 2 /* 3926C */
183#define ENE_HW_D 3 /* 3926D or later */
184
185#define ene_printk(level, text, ...) \
186 printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__)
187
188#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__)
189#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__)
190
191
192#define __dbg(level, format, ...) \
193 do { \
194 if (debug >= level) \
195 printk(KERN_DEBUG ENE_DRIVER_NAME \
196 ": " format "\n", ## __VA_ARGS__); \
197 } while (0)
198
199
200#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__)
201#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__)
202#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__)
203
204#define MS_TO_NS(msec) ((msec) * 1000)
205
206struct ene_device {
207 struct pnp_dev *pnp_dev;
208 struct rc_dev *rdev;
209
210 /* hw IO settings */
211 long hw_io;
212 int irq;
213 spinlock_t hw_lock;
214
215 /* HW features */
216 int hw_revision; /* hardware revision */
217 bool hw_use_gpio_0a; /* gpio0a is demodulated input*/
218 bool hw_extra_buffer; /* hardware has 'extra buffer' */
219 bool hw_fan_input; /* fan input is IR data source */
220 bool hw_learning_and_tx_capable; /* learning & tx capable */
221 int pll_freq;
222 int buffer_len;
223
224 /* Extra RX buffer location */
225 int extra_buf1_address;
226 int extra_buf1_len;
227 int extra_buf2_address;
228 int extra_buf2_len;
229
230 /* HW state*/
231 int r_pointer; /* pointer to next sample to read */
232 int w_pointer; /* pointer to next sample hw will write */
233 bool rx_fan_input_inuse; /* is fan input in use for rx*/
234 int tx_reg; /* current reg used for TX */
235 u8 saved_conf1; /* saved FEC0 reg */
236 unsigned int tx_sample; /* current sample for TX */
237 bool tx_sample_pulse; /* current sample is pulse */
238
239 /* TX buffer */
240 int *tx_buffer; /* input samples buffer*/
241 int tx_pos; /* position in that bufer */
242 int tx_len; /* current len of tx buffer */
243 int tx_done; /* done transmitting */
244 /* one more sample pending*/
245 struct completion tx_complete; /* TX completion */
246 struct timer_list tx_sim_timer;
247
248 /* TX settings */
249 int tx_period;
250 int tx_duty_cycle;
251 int transmitter_mask;
252
253 /* RX settings */
254 bool learning_mode_enabled; /* learning input enabled */
255 bool carrier_detect_enabled; /* carrier detect enabled */
256 int rx_period_adjust;
257 bool rx_enabled;
258};
259
260static int ene_irq_status(struct ene_device *dev);
261static void ene_rx_read_hw_pointer(struct ene_device *dev);
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
new file mode 100644
index 000000000000..6811512b4e83
--- /dev/null
+++ b/drivers/media/rc/imon.c
@@ -0,0 +1,2457 @@
1/*
2 * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD
3 *
4 * Copyright(C) 2010 Jarod Wilson <jarod@wilsonet.com>
5 * Portions based on the original lirc_imon driver,
6 * Copyright(C) 2004 Venky Raju(dev@venky.ws)
7 *
8 * Huge thanks to R. Geoff Newbury for invaluable debugging on the
9 * 0xffdc iMON devices, and for sending me one to hack on, without
10 * which the support for them wouldn't be nearly as good. Thanks
11 * also to the numerous 0xffdc device owners that tested auto-config
12 * support for me and provided debug dumps from their devices.
13 *
14 * imon is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
30
31#include <linux/errno.h>
32#include <linux/init.h>
33#include <linux/kernel.h>
34#include <linux/module.h>
35#include <linux/slab.h>
36#include <linux/uaccess.h>
37
38#include <linux/input.h>
39#include <linux/usb.h>
40#include <linux/usb/input.h>
41#include <media/rc-core.h>
42
43#include <linux/time.h>
44#include <linux/timer.h>
45
46#define MOD_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
47#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display"
48#define MOD_NAME "imon"
49#define MOD_VERSION "0.9.2"
50
51#define DISPLAY_MINOR_BASE 144
52#define DEVICE_NAME "lcd%d"
53
54#define BUF_CHUNK_SIZE 8
55#define BUF_SIZE 128
56
57#define BIT_DURATION 250 /* each bit received is 250us */
58
59#define IMON_CLOCK_ENABLE_PACKETS 2
60
61/*** P R O T O T Y P E S ***/
62
63/* USB Callback prototypes */
64static int imon_probe(struct usb_interface *interface,
65 const struct usb_device_id *id);
66static void imon_disconnect(struct usb_interface *interface);
67static void usb_rx_callback_intf0(struct urb *urb);
68static void usb_rx_callback_intf1(struct urb *urb);
69static void usb_tx_callback(struct urb *urb);
70
71/* suspend/resume support */
72static int imon_resume(struct usb_interface *intf);
73static int imon_suspend(struct usb_interface *intf, pm_message_t message);
74
75/* Display file_operations function prototypes */
76static int display_open(struct inode *inode, struct file *file);
77static int display_close(struct inode *inode, struct file *file);
78
79/* VFD write operation */
80static ssize_t vfd_write(struct file *file, const char *buf,
81 size_t n_bytes, loff_t *pos);
82
83/* LCD file_operations override function prototypes */
84static ssize_t lcd_write(struct file *file, const char *buf,
85 size_t n_bytes, loff_t *pos);
86
87/*** G L O B A L S ***/
88
89struct imon_context {
90 struct device *dev;
91 /* Newer devices have two interfaces */
92 struct usb_device *usbdev_intf0;
93 struct usb_device *usbdev_intf1;
94
95 bool display_supported; /* not all controllers do */
96 bool display_isopen; /* display port has been opened */
97 bool rf_device; /* true if iMON 2.4G LT/DT RF device */
98 bool rf_isassociating; /* RF remote associating */
99 bool dev_present_intf0; /* USB device presence, interface 0 */
100 bool dev_present_intf1; /* USB device presence, interface 1 */
101
102 struct mutex lock; /* to lock this object */
103 wait_queue_head_t remove_ok; /* For unexpected USB disconnects */
104
105 struct usb_endpoint_descriptor *rx_endpoint_intf0;
106 struct usb_endpoint_descriptor *rx_endpoint_intf1;
107 struct usb_endpoint_descriptor *tx_endpoint;
108 struct urb *rx_urb_intf0;
109 struct urb *rx_urb_intf1;
110 struct urb *tx_urb;
111 bool tx_control;
112 unsigned char usb_rx_buf[8];
113 unsigned char usb_tx_buf[8];
114
115 struct tx_t {
116 unsigned char data_buf[35]; /* user data buffer */
117 struct completion finished; /* wait for write to finish */
118 bool busy; /* write in progress */
119 int status; /* status of tx completion */
120 } tx;
121
122 u16 vendor; /* usb vendor ID */
123 u16 product; /* usb product ID */
124
125 struct rc_dev *rdev; /* rc-core device for remote */
126 struct input_dev *idev; /* input device for panel & IR mouse */
127 struct input_dev *touch; /* input device for touchscreen */
128
129 spinlock_t kc_lock; /* make sure we get keycodes right */
130 u32 kc; /* current input keycode */
131 u32 last_keycode; /* last reported input keycode */
132 u32 rc_scancode; /* the computed remote scancode */
133 u8 rc_toggle; /* the computed remote toggle bit */
134 u64 rc_type; /* iMON or MCE (RC6) IR protocol? */
135 bool release_code; /* some keys send a release code */
136
137 u8 display_type; /* store the display type */
138 bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */
139
140 char name_rdev[128]; /* rc input device name */
141 char phys_rdev[64]; /* rc input device phys path */
142
143 char name_idev[128]; /* input device name */
144 char phys_idev[64]; /* input device phys path */
145
146 char name_touch[128]; /* touch screen name */
147 char phys_touch[64]; /* touch screen phys path */
148 struct timer_list ttimer; /* touch screen timer */
149 int touch_x; /* x coordinate on touchscreen */
150 int touch_y; /* y coordinate on touchscreen */
151};
152
153#define TOUCH_TIMEOUT (HZ/30)
154
155/* vfd character device file operations */
156static const struct file_operations vfd_fops = {
157 .owner = THIS_MODULE,
158 .open = &display_open,
159 .write = &vfd_write,
160 .release = &display_close,
161 .llseek = noop_llseek,
162};
163
164/* lcd character device file operations */
165static const struct file_operations lcd_fops = {
166 .owner = THIS_MODULE,
167 .open = &display_open,
168 .write = &lcd_write,
169 .release = &display_close,
170 .llseek = noop_llseek,
171};
172
173enum {
174 IMON_DISPLAY_TYPE_AUTO = 0,
175 IMON_DISPLAY_TYPE_VFD = 1,
176 IMON_DISPLAY_TYPE_LCD = 2,
177 IMON_DISPLAY_TYPE_VGA = 3,
178 IMON_DISPLAY_TYPE_NONE = 4,
179};
180
181enum {
182 IMON_KEY_IMON = 0,
183 IMON_KEY_MCE = 1,
184 IMON_KEY_PANEL = 2,
185};
186
187/*
188 * USB Device ID for iMON USB Control Boards
189 *
190 * The Windows drivers contain 6 different inf files, more or less one for
191 * each new device until the 0x0034-0x0046 devices, which all use the same
192 * driver. Some of the devices in the 34-46 range haven't been definitively
193 * identified yet. Early devices have either a TriGem Computer, Inc. or a
194 * Samsung vendor ID (0x0aa8 and 0x04e8 respectively), while all later
195 * devices use the SoundGraph vendor ID (0x15c2). This driver only supports
196 * the ffdc and later devices, which do onboard decoding.
197 */
198static struct usb_device_id imon_usb_id_table[] = {
199 /*
200 * Several devices with this same device ID, all use iMON_PAD.inf
201 * SoundGraph iMON PAD (IR & VFD)
202 * SoundGraph iMON PAD (IR & LCD)
203 * SoundGraph iMON Knob (IR only)
204 */
205 { USB_DEVICE(0x15c2, 0xffdc) },
206
207 /*
208 * Newer devices, all driven by the latest iMON Windows driver, full
209 * list of device IDs extracted via 'strings Setup/data1.hdr |grep 15c2'
210 * Need user input to fill in details on unknown devices.
211 */
212 /* SoundGraph iMON OEM Touch LCD (IR & 7" VGA LCD) */
213 { USB_DEVICE(0x15c2, 0x0034) },
214 /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */
215 { USB_DEVICE(0x15c2, 0x0035) },
216 /* SoundGraph iMON OEM VFD (IR & VFD) */
217 { USB_DEVICE(0x15c2, 0x0036) },
218 /* device specifics unknown */
219 { USB_DEVICE(0x15c2, 0x0037) },
220 /* SoundGraph iMON OEM LCD (IR & LCD) */
221 { USB_DEVICE(0x15c2, 0x0038) },
222 /* SoundGraph iMON UltraBay (IR & LCD) */
223 { USB_DEVICE(0x15c2, 0x0039) },
224 /* device specifics unknown */
225 { USB_DEVICE(0x15c2, 0x003a) },
226 /* device specifics unknown */
227 { USB_DEVICE(0x15c2, 0x003b) },
228 /* SoundGraph iMON OEM Inside (IR only) */
229 { USB_DEVICE(0x15c2, 0x003c) },
230 /* device specifics unknown */
231 { USB_DEVICE(0x15c2, 0x003d) },
232 /* device specifics unknown */
233 { USB_DEVICE(0x15c2, 0x003e) },
234 /* device specifics unknown */
235 { USB_DEVICE(0x15c2, 0x003f) },
236 /* device specifics unknown */
237 { USB_DEVICE(0x15c2, 0x0040) },
238 /* SoundGraph iMON MINI (IR only) */
239 { USB_DEVICE(0x15c2, 0x0041) },
240 /* Antec Veris Multimedia Station EZ External (IR only) */
241 { USB_DEVICE(0x15c2, 0x0042) },
242 /* Antec Veris Multimedia Station Basic Internal (IR only) */
243 { USB_DEVICE(0x15c2, 0x0043) },
244 /* Antec Veris Multimedia Station Elite (IR & VFD) */
245 { USB_DEVICE(0x15c2, 0x0044) },
246 /* Antec Veris Multimedia Station Premiere (IR & LCD) */
247 { USB_DEVICE(0x15c2, 0x0045) },
248 /* device specifics unknown */
249 { USB_DEVICE(0x15c2, 0x0046) },
250 {}
251};
252
253/* USB Device data */
254static struct usb_driver imon_driver = {
255 .name = MOD_NAME,
256 .probe = imon_probe,
257 .disconnect = imon_disconnect,
258 .suspend = imon_suspend,
259 .resume = imon_resume,
260 .id_table = imon_usb_id_table,
261};
262
263static struct usb_class_driver imon_vfd_class = {
264 .name = DEVICE_NAME,
265 .fops = &vfd_fops,
266 .minor_base = DISPLAY_MINOR_BASE,
267};
268
269static struct usb_class_driver imon_lcd_class = {
270 .name = DEVICE_NAME,
271 .fops = &lcd_fops,
272 .minor_base = DISPLAY_MINOR_BASE,
273};
274
275/* imon receiver front panel/knob key table */
276static const struct {
277 u64 hw_code;
278 u32 keycode;
279} imon_panel_key_table[] = {
280 { 0x000000000f00ffeell, KEY_PROG1 }, /* Go */
281 { 0x000000001f00ffeell, KEY_AUDIO },
282 { 0x000000002000ffeell, KEY_VIDEO },
283 { 0x000000002100ffeell, KEY_CAMERA },
284 { 0x000000002700ffeell, KEY_DVD },
285 { 0x000000002300ffeell, KEY_TV },
286 { 0x000000000500ffeell, KEY_PREVIOUS },
287 { 0x000000000700ffeell, KEY_REWIND },
288 { 0x000000000400ffeell, KEY_STOP },
289 { 0x000000003c00ffeell, KEY_PLAYPAUSE },
290 { 0x000000000800ffeell, KEY_FASTFORWARD },
291 { 0x000000000600ffeell, KEY_NEXT },
292 { 0x000000010000ffeell, KEY_RIGHT },
293 { 0x000001000000ffeell, KEY_LEFT },
294 { 0x000000003d00ffeell, KEY_SELECT },
295 { 0x000100000000ffeell, KEY_VOLUMEUP },
296 { 0x010000000000ffeell, KEY_VOLUMEDOWN },
297 { 0x000000000100ffeell, KEY_MUTE },
298 /* 0xffdc iMON MCE VFD */
299 { 0x00010000ffffffeell, KEY_VOLUMEUP },
300 { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
301 /* iMON Knob values */
302 { 0x000100ffffffffeell, KEY_VOLUMEUP },
303 { 0x010000ffffffffeell, KEY_VOLUMEDOWN },
304 { 0x000008ffffffffeell, KEY_MUTE },
305};
306
307/* to prevent races between open() and disconnect(), probing, etc */
308static DEFINE_MUTEX(driver_lock);
309
310/* Module bookkeeping bits */
311MODULE_AUTHOR(MOD_AUTHOR);
312MODULE_DESCRIPTION(MOD_DESC);
313MODULE_VERSION(MOD_VERSION);
314MODULE_LICENSE("GPL");
315MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
316
317static bool debug;
318module_param(debug, bool, S_IRUGO | S_IWUSR);
319MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
320
321/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
322static int display_type;
323module_param(display_type, int, S_IRUGO);
324MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, "
325 "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)");
326
327static int pad_stabilize = 1;
328module_param(pad_stabilize, int, S_IRUGO | S_IWUSR);
329MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD "
330 "presses in arrow key mode. 0=disable, 1=enable (default).");
331
332/*
333 * In certain use cases, mouse mode isn't really helpful, and could actually
334 * cause confusion, so allow disabling it when the IR device is open.
335 */
336static bool nomouse;
337module_param(nomouse, bool, S_IRUGO | S_IWUSR);
338MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is "
339 "open. 0=don't disable, 1=disable. (default: don't disable)");
340
341/* threshold at which a pad push registers as an arrow key in kbd mode */
342static int pad_thresh;
343module_param(pad_thresh, int, S_IRUGO | S_IWUSR);
344MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an "
345 "arrow key in kbd mode (default: 28)");
346
347
348static void free_imon_context(struct imon_context *ictx)
349{
350 struct device *dev = ictx->dev;
351
352 usb_free_urb(ictx->tx_urb);
353 usb_free_urb(ictx->rx_urb_intf0);
354 usb_free_urb(ictx->rx_urb_intf1);
355 kfree(ictx);
356
357 dev_dbg(dev, "%s: iMON context freed\n", __func__);
358}
359
360/**
361 * Called when the Display device (e.g. /dev/lcd0)
362 * is opened by the application.
363 */
364static int display_open(struct inode *inode, struct file *file)
365{
366 struct usb_interface *interface;
367 struct imon_context *ictx = NULL;
368 int subminor;
369 int retval = 0;
370
371 /* prevent races with disconnect */
372 mutex_lock(&driver_lock);
373
374 subminor = iminor(inode);
375 interface = usb_find_interface(&imon_driver, subminor);
376 if (!interface) {
377 pr_err("could not find interface for minor %d\n", subminor);
378 retval = -ENODEV;
379 goto exit;
380 }
381 ictx = usb_get_intfdata(interface);
382
383 if (!ictx) {
384 pr_err("no context found for minor %d\n", subminor);
385 retval = -ENODEV;
386 goto exit;
387 }
388
389 mutex_lock(&ictx->lock);
390
391 if (!ictx->display_supported) {
392 pr_err("display not supported by device\n");
393 retval = -ENODEV;
394 } else if (ictx->display_isopen) {
395 pr_err("display port is already open\n");
396 retval = -EBUSY;
397 } else {
398 ictx->display_isopen = true;
399 file->private_data = ictx;
400 dev_dbg(ictx->dev, "display port opened\n");
401 }
402
403 mutex_unlock(&ictx->lock);
404
405exit:
406 mutex_unlock(&driver_lock);
407 return retval;
408}
409
410/**
411 * Called when the display device (e.g. /dev/lcd0)
412 * is closed by the application.
413 */
414static int display_close(struct inode *inode, struct file *file)
415{
416 struct imon_context *ictx = NULL;
417 int retval = 0;
418
419 ictx = file->private_data;
420
421 if (!ictx) {
422 pr_err("no context for device\n");
423 return -ENODEV;
424 }
425
426 mutex_lock(&ictx->lock);
427
428 if (!ictx->display_supported) {
429 pr_err("display not supported by device\n");
430 retval = -ENODEV;
431 } else if (!ictx->display_isopen) {
432 pr_err("display is not open\n");
433 retval = -EIO;
434 } else {
435 ictx->display_isopen = false;
436 dev_dbg(ictx->dev, "display port closed\n");
437 if (!ictx->dev_present_intf0) {
438 /*
439 * Device disconnected before close and IR port is not
440 * open. If IR port is open, context will be deleted by
441 * ir_close.
442 */
443 mutex_unlock(&ictx->lock);
444 free_imon_context(ictx);
445 return retval;
446 }
447 }
448
449 mutex_unlock(&ictx->lock);
450 return retval;
451}
452
453/**
454 * Sends a packet to the device -- this function must be called
455 * with ictx->lock held.
456 */
457static int send_packet(struct imon_context *ictx)
458{
459 unsigned int pipe;
460 unsigned long timeout;
461 int interval = 0;
462 int retval = 0;
463 struct usb_ctrlrequest *control_req = NULL;
464
465 /* Check if we need to use control or interrupt urb */
466 if (!ictx->tx_control) {
467 pipe = usb_sndintpipe(ictx->usbdev_intf0,
468 ictx->tx_endpoint->bEndpointAddress);
469 interval = ictx->tx_endpoint->bInterval;
470
471 usb_fill_int_urb(ictx->tx_urb, ictx->usbdev_intf0, pipe,
472 ictx->usb_tx_buf,
473 sizeof(ictx->usb_tx_buf),
474 usb_tx_callback, ictx, interval);
475
476 ictx->tx_urb->actual_length = 0;
477 } else {
478 /* fill request into kmalloc'ed space: */
479 control_req = kmalloc(sizeof(struct usb_ctrlrequest),
480 GFP_KERNEL);
481 if (control_req == NULL)
482 return -ENOMEM;
483
484 /* setup packet is '21 09 0200 0001 0008' */
485 control_req->bRequestType = 0x21;
486 control_req->bRequest = 0x09;
487 control_req->wValue = cpu_to_le16(0x0200);
488 control_req->wIndex = cpu_to_le16(0x0001);
489 control_req->wLength = cpu_to_le16(0x0008);
490
491 /* control pipe is endpoint 0x00 */
492 pipe = usb_sndctrlpipe(ictx->usbdev_intf0, 0);
493
494 /* build the control urb */
495 usb_fill_control_urb(ictx->tx_urb, ictx->usbdev_intf0,
496 pipe, (unsigned char *)control_req,
497 ictx->usb_tx_buf,
498 sizeof(ictx->usb_tx_buf),
499 usb_tx_callback, ictx);
500 ictx->tx_urb->actual_length = 0;
501 }
502
503 init_completion(&ictx->tx.finished);
504 ictx->tx.busy = true;
505 smp_rmb(); /* ensure later readers know we're busy */
506
507 retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
508 if (retval) {
509 ictx->tx.busy = false;
510 smp_rmb(); /* ensure later readers know we're not busy */
511 pr_err("error submitting urb(%d)\n", retval);
512 } else {
513 /* Wait for transmission to complete (or abort) */
514 mutex_unlock(&ictx->lock);
515 retval = wait_for_completion_interruptible(
516 &ictx->tx.finished);
517 if (retval)
518 pr_err("task interrupted\n");
519 mutex_lock(&ictx->lock);
520
521 retval = ictx->tx.status;
522 if (retval)
523 pr_err("packet tx failed (%d)\n", retval);
524 }
525
526 kfree(control_req);
527
528 /*
529 * Induce a mandatory 5ms delay before returning, as otherwise,
530 * send_packet can get called so rapidly as to overwhelm the device,
531 * particularly on faster systems and/or those with quirky usb.
532 */
533 timeout = msecs_to_jiffies(5);
534 set_current_state(TASK_UNINTERRUPTIBLE);
535 schedule_timeout(timeout);
536
537 return retval;
538}
539
540/**
541 * Sends an associate packet to the iMON 2.4G.
542 *
543 * This might not be such a good idea, since it has an id collision with
544 * some versions of the "IR & VFD" combo. The only way to determine if it
545 * is an RF version is to look at the product description string. (Which
546 * we currently do not fetch).
547 */
548static int send_associate_24g(struct imon_context *ictx)
549{
550 int retval;
551 const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00,
552 0x00, 0x00, 0x00, 0x20 };
553
554 if (!ictx) {
555 pr_err("no context for device\n");
556 return -ENODEV;
557 }
558
559 if (!ictx->dev_present_intf0) {
560 pr_err("no iMON device present\n");
561 return -ENODEV;
562 }
563
564 memcpy(ictx->usb_tx_buf, packet, sizeof(packet));
565 retval = send_packet(ictx);
566
567 return retval;
568}
569
570/**
571 * Sends packets to setup and show clock on iMON display
572 *
573 * Arguments: year - last 2 digits of year, month - 1..12,
574 * day - 1..31, dow - day of the week (0-Sun...6-Sat),
575 * hour - 0..23, minute - 0..59, second - 0..59
576 */
577static int send_set_imon_clock(struct imon_context *ictx,
578 unsigned int year, unsigned int month,
579 unsigned int day, unsigned int dow,
580 unsigned int hour, unsigned int minute,
581 unsigned int second)
582{
583 unsigned char clock_enable_pkt[IMON_CLOCK_ENABLE_PACKETS][8];
584 int retval = 0;
585 int i;
586
587 if (!ictx) {
588 pr_err("no context for device\n");
589 return -ENODEV;
590 }
591
592 switch (ictx->display_type) {
593 case IMON_DISPLAY_TYPE_LCD:
594 clock_enable_pkt[0][0] = 0x80;
595 clock_enable_pkt[0][1] = year;
596 clock_enable_pkt[0][2] = month-1;
597 clock_enable_pkt[0][3] = day;
598 clock_enable_pkt[0][4] = hour;
599 clock_enable_pkt[0][5] = minute;
600 clock_enable_pkt[0][6] = second;
601
602 clock_enable_pkt[1][0] = 0x80;
603 clock_enable_pkt[1][1] = 0;
604 clock_enable_pkt[1][2] = 0;
605 clock_enable_pkt[1][3] = 0;
606 clock_enable_pkt[1][4] = 0;
607 clock_enable_pkt[1][5] = 0;
608 clock_enable_pkt[1][6] = 0;
609
610 if (ictx->product == 0xffdc) {
611 clock_enable_pkt[0][7] = 0x50;
612 clock_enable_pkt[1][7] = 0x51;
613 } else {
614 clock_enable_pkt[0][7] = 0x88;
615 clock_enable_pkt[1][7] = 0x8a;
616 }
617
618 break;
619
620 case IMON_DISPLAY_TYPE_VFD:
621 clock_enable_pkt[0][0] = year;
622 clock_enable_pkt[0][1] = month-1;
623 clock_enable_pkt[0][2] = day;
624 clock_enable_pkt[0][3] = dow;
625 clock_enable_pkt[0][4] = hour;
626 clock_enable_pkt[0][5] = minute;
627 clock_enable_pkt[0][6] = second;
628 clock_enable_pkt[0][7] = 0x40;
629
630 clock_enable_pkt[1][0] = 0;
631 clock_enable_pkt[1][1] = 0;
632 clock_enable_pkt[1][2] = 1;
633 clock_enable_pkt[1][3] = 0;
634 clock_enable_pkt[1][4] = 0;
635 clock_enable_pkt[1][5] = 0;
636 clock_enable_pkt[1][6] = 0;
637 clock_enable_pkt[1][7] = 0x42;
638
639 break;
640
641 default:
642 return -ENODEV;
643 }
644
645 for (i = 0; i < IMON_CLOCK_ENABLE_PACKETS; i++) {
646 memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8);
647 retval = send_packet(ictx);
648 if (retval) {
649 pr_err("send_packet failed for packet %d\n", i);
650 break;
651 }
652 }
653
654 return retval;
655}
656
657/**
658 * These are the sysfs functions to handle the association on the iMON 2.4G LT.
659 */
660static ssize_t show_associate_remote(struct device *d,
661 struct device_attribute *attr,
662 char *buf)
663{
664 struct imon_context *ictx = dev_get_drvdata(d);
665
666 if (!ictx)
667 return -ENODEV;
668
669 mutex_lock(&ictx->lock);
670 if (ictx->rf_isassociating)
671 strcpy(buf, "associating\n");
672 else
673 strcpy(buf, "closed\n");
674
675 dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for "
676 "instructions on how to associate your iMON 2.4G DT/LT "
677 "remote\n");
678 mutex_unlock(&ictx->lock);
679 return strlen(buf);
680}
681
682static ssize_t store_associate_remote(struct device *d,
683 struct device_attribute *attr,
684 const char *buf, size_t count)
685{
686 struct imon_context *ictx;
687
688 ictx = dev_get_drvdata(d);
689
690 if (!ictx)
691 return -ENODEV;
692
693 mutex_lock(&ictx->lock);
694 ictx->rf_isassociating = true;
695 send_associate_24g(ictx);
696 mutex_unlock(&ictx->lock);
697
698 return count;
699}
700
701/**
702 * sysfs functions to control internal imon clock
703 */
704static ssize_t show_imon_clock(struct device *d,
705 struct device_attribute *attr, char *buf)
706{
707 struct imon_context *ictx = dev_get_drvdata(d);
708 size_t len;
709
710 if (!ictx)
711 return -ENODEV;
712
713 mutex_lock(&ictx->lock);
714
715 if (!ictx->display_supported) {
716 len = snprintf(buf, PAGE_SIZE, "Not supported.");
717 } else {
718 len = snprintf(buf, PAGE_SIZE,
719 "To set the clock on your iMON display:\n"
720 "# date \"+%%y %%m %%d %%w %%H %%M %%S\" > imon_clock\n"
721 "%s", ictx->display_isopen ?
722 "\nNOTE: imon device must be closed\n" : "");
723 }
724
725 mutex_unlock(&ictx->lock);
726
727 return len;
728}
729
730static ssize_t store_imon_clock(struct device *d,
731 struct device_attribute *attr,
732 const char *buf, size_t count)
733{
734 struct imon_context *ictx = dev_get_drvdata(d);
735 ssize_t retval;
736 unsigned int year, month, day, dow, hour, minute, second;
737
738 if (!ictx)
739 return -ENODEV;
740
741 mutex_lock(&ictx->lock);
742
743 if (!ictx->display_supported) {
744 retval = -ENODEV;
745 goto exit;
746 } else if (ictx->display_isopen) {
747 retval = -EBUSY;
748 goto exit;
749 }
750
751 if (sscanf(buf, "%u %u %u %u %u %u %u", &year, &month, &day, &dow,
752 &hour, &minute, &second) != 7) {
753 retval = -EINVAL;
754 goto exit;
755 }
756
757 if ((month < 1 || month > 12) ||
758 (day < 1 || day > 31) || (dow > 6) ||
759 (hour > 23) || (minute > 59) || (second > 59)) {
760 retval = -EINVAL;
761 goto exit;
762 }
763
764 retval = send_set_imon_clock(ictx, year, month, day, dow,
765 hour, minute, second);
766 if (retval)
767 goto exit;
768
769 retval = count;
770exit:
771 mutex_unlock(&ictx->lock);
772
773 return retval;
774}
775
776
777static DEVICE_ATTR(imon_clock, S_IWUSR | S_IRUGO, show_imon_clock,
778 store_imon_clock);
779
780static DEVICE_ATTR(associate_remote, S_IWUSR | S_IRUGO, show_associate_remote,
781 store_associate_remote);
782
783static struct attribute *imon_display_sysfs_entries[] = {
784 &dev_attr_imon_clock.attr,
785 NULL
786};
787
788static struct attribute_group imon_display_attr_group = {
789 .attrs = imon_display_sysfs_entries
790};
791
792static struct attribute *imon_rf_sysfs_entries[] = {
793 &dev_attr_associate_remote.attr,
794 NULL
795};
796
797static struct attribute_group imon_rf_attr_group = {
798 .attrs = imon_rf_sysfs_entries
799};
800
801/**
802 * Writes data to the VFD. The iMON VFD is 2x16 characters
803 * and requires data in 5 consecutive USB interrupt packets,
804 * each packet but the last carrying 7 bytes.
805 *
806 * I don't know if the VFD board supports features such as
807 * scrolling, clearing rows, blanking, etc. so at
808 * the caller must provide a full screen of data. If fewer
809 * than 32 bytes are provided spaces will be appended to
810 * generate a full screen.
811 */
812static ssize_t vfd_write(struct file *file, const char *buf,
813 size_t n_bytes, loff_t *pos)
814{
815 int i;
816 int offset;
817 int seq;
818 int retval = 0;
819 struct imon_context *ictx;
820 const unsigned char vfd_packet6[] = {
821 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
822
823 ictx = file->private_data;
824 if (!ictx) {
825 pr_err("no context for device\n");
826 return -ENODEV;
827 }
828
829 mutex_lock(&ictx->lock);
830
831 if (!ictx->dev_present_intf0) {
832 pr_err("no iMON device present\n");
833 retval = -ENODEV;
834 goto exit;
835 }
836
837 if (n_bytes <= 0 || n_bytes > 32) {
838 pr_err("invalid payload size\n");
839 retval = -EINVAL;
840 goto exit;
841 }
842
843 if (copy_from_user(ictx->tx.data_buf, buf, n_bytes)) {
844 retval = -EFAULT;
845 goto exit;
846 }
847
848 /* Pad with spaces */
849 for (i = n_bytes; i < 32; ++i)
850 ictx->tx.data_buf[i] = ' ';
851
852 for (i = 32; i < 35; ++i)
853 ictx->tx.data_buf[i] = 0xFF;
854
855 offset = 0;
856 seq = 0;
857
858 do {
859 memcpy(ictx->usb_tx_buf, ictx->tx.data_buf + offset, 7);
860 ictx->usb_tx_buf[7] = (unsigned char) seq;
861
862 retval = send_packet(ictx);
863 if (retval) {
864 pr_err("send packet failed for packet #%d\n", seq / 2);
865 goto exit;
866 } else {
867 seq += 2;
868 offset += 7;
869 }
870
871 } while (offset < 35);
872
873 /* Send packet #6 */
874 memcpy(ictx->usb_tx_buf, &vfd_packet6, sizeof(vfd_packet6));
875 ictx->usb_tx_buf[7] = (unsigned char) seq;
876 retval = send_packet(ictx);
877 if (retval)
878 pr_err("send packet failed for packet #%d\n", seq / 2);
879
880exit:
881 mutex_unlock(&ictx->lock);
882
883 return (!retval) ? n_bytes : retval;
884}
885
886/**
887 * Writes data to the LCD. The iMON OEM LCD screen expects 8-byte
888 * packets. We accept data as 16 hexadecimal digits, followed by a
889 * newline (to make it easy to drive the device from a command-line
890 * -- even though the actual binary data is a bit complicated).
891 *
892 * The device itself is not a "traditional" text-mode display. It's
893 * actually a 16x96 pixel bitmap display. That means if you want to
894 * display text, you've got to have your own "font" and translate the
895 * text into bitmaps for display. This is really flexible (you can
896 * display whatever diacritics you need, and so on), but it's also
897 * a lot more complicated than most LCDs...
898 */
899static ssize_t lcd_write(struct file *file, const char *buf,
900 size_t n_bytes, loff_t *pos)
901{
902 int retval = 0;
903 struct imon_context *ictx;
904
905 ictx = file->private_data;
906 if (!ictx) {
907 pr_err("no context for device\n");
908 return -ENODEV;
909 }
910
911 mutex_lock(&ictx->lock);
912
913 if (!ictx->display_supported) {
914 pr_err("no iMON display present\n");
915 retval = -ENODEV;
916 goto exit;
917 }
918
919 if (n_bytes != 8) {
920 pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes);
921 retval = -EINVAL;
922 goto exit;
923 }
924
925 if (copy_from_user(ictx->usb_tx_buf, buf, 8)) {
926 retval = -EFAULT;
927 goto exit;
928 }
929
930 retval = send_packet(ictx);
931 if (retval) {
932 pr_err("send packet failed!\n");
933 goto exit;
934 } else {
935 dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
936 __func__, (int) n_bytes);
937 }
938exit:
939 mutex_unlock(&ictx->lock);
940 return (!retval) ? n_bytes : retval;
941}
942
943/**
944 * Callback function for USB core API: transmit data
945 */
946static void usb_tx_callback(struct urb *urb)
947{
948 struct imon_context *ictx;
949
950 if (!urb)
951 return;
952 ictx = (struct imon_context *)urb->context;
953 if (!ictx)
954 return;
955
956 ictx->tx.status = urb->status;
957
958 /* notify waiters that write has finished */
959 ictx->tx.busy = false;
960 smp_rmb(); /* ensure later readers know we're not busy */
961 complete(&ictx->tx.finished);
962}
963
964/**
965 * report touchscreen input
966 */
967static void imon_touch_display_timeout(unsigned long data)
968{
969 struct imon_context *ictx = (struct imon_context *)data;
970
971 if (ictx->display_type != IMON_DISPLAY_TYPE_VGA)
972 return;
973
974 input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
975 input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
976 input_report_key(ictx->touch, BTN_TOUCH, 0x00);
977 input_sync(ictx->touch);
978}
979
980/**
981 * iMON IR receivers support two different signal sets -- those used by
982 * the iMON remotes, and those used by the Windows MCE remotes (which is
983 * really just RC-6), but only one or the other at a time, as the signals
984 * are decoded onboard the receiver.
985 */
986static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
987{
988 int retval;
989 struct imon_context *ictx = rc->priv;
990 struct device *dev = ictx->dev;
991 bool pad_mouse;
992 unsigned char ir_proto_packet[] = {
993 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
994
995 if (rc_type && !(rc_type & rc->allowed_protos))
996 dev_warn(dev, "Looks like you're trying to use an IR protocol "
997 "this device does not support\n");
998
999 switch (rc_type) {
1000 case RC_TYPE_RC6:
1001 dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
1002 ir_proto_packet[0] = 0x01;
1003 pad_mouse = false;
1004 break;
1005 case RC_TYPE_UNKNOWN:
1006 case RC_TYPE_OTHER:
1007 dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
1008 if (pad_stabilize && !nomouse)
1009 pad_mouse = true;
1010 else {
1011 dev_dbg(dev, "PAD stabilize functionality disabled\n");
1012 pad_mouse = false;
1013 }
1014 /* ir_proto_packet[0] = 0x00; // already the default */
1015 rc_type = RC_TYPE_OTHER;
1016 break;
1017 default:
1018 dev_warn(dev, "Unsupported IR protocol specified, overriding "
1019 "to iMON IR protocol\n");
1020 if (pad_stabilize && !nomouse)
1021 pad_mouse = true;
1022 else {
1023 dev_dbg(dev, "PAD stabilize functionality disabled\n");
1024 pad_mouse = false;
1025 }
1026 /* ir_proto_packet[0] = 0x00; // already the default */
1027 rc_type = RC_TYPE_OTHER;
1028 break;
1029 }
1030
1031 memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
1032
1033 retval = send_packet(ictx);
1034 if (retval)
1035 goto out;
1036
1037 ictx->rc_type = rc_type;
1038 ictx->pad_mouse = pad_mouse;
1039
1040out:
1041 return retval;
1042}
1043
1044static inline int tv2int(const struct timeval *a, const struct timeval *b)
1045{
1046 int usecs = 0;
1047 int sec = 0;
1048
1049 if (b->tv_usec > a->tv_usec) {
1050 usecs = 1000000;
1051 sec--;
1052 }
1053
1054 usecs += a->tv_usec - b->tv_usec;
1055
1056 sec += a->tv_sec - b->tv_sec;
1057 sec *= 1000;
1058 usecs /= 1000;
1059 sec += usecs;
1060
1061 if (sec < 0)
1062 sec = 1000;
1063
1064 return sec;
1065}
1066
1067/**
1068 * The directional pad behaves a bit differently, depending on whether this is
1069 * one of the older ffdc devices or a newer device. Newer devices appear to
1070 * have a higher resolution matrix for more precise mouse movement, but it
1071 * makes things overly sensitive in keyboard mode, so we do some interesting
1072 * contortions to make it less touchy. Older devices run through the same
1073 * routine with shorter timeout and a smaller threshold.
1074 */
1075static int stabilize(int a, int b, u16 timeout, u16 threshold)
1076{
1077 struct timeval ct;
1078 static struct timeval prev_time = {0, 0};
1079 static struct timeval hit_time = {0, 0};
1080 static int x, y, prev_result, hits;
1081 int result = 0;
1082 int msec, msec_hit;
1083
1084 do_gettimeofday(&ct);
1085 msec = tv2int(&ct, &prev_time);
1086 msec_hit = tv2int(&ct, &hit_time);
1087
1088 if (msec > 100) {
1089 x = 0;
1090 y = 0;
1091 hits = 0;
1092 }
1093
1094 x += a;
1095 y += b;
1096
1097 prev_time = ct;
1098
1099 if (abs(x) > threshold || abs(y) > threshold) {
1100 if (abs(y) > abs(x))
1101 result = (y > 0) ? 0x7F : 0x80;
1102 else
1103 result = (x > 0) ? 0x7F00 : 0x8000;
1104
1105 x = 0;
1106 y = 0;
1107
1108 if (result == prev_result) {
1109 hits++;
1110
1111 if (hits > 3) {
1112 switch (result) {
1113 case 0x7F:
1114 y = 17 * threshold / 30;
1115 break;
1116 case 0x80:
1117 y -= 17 * threshold / 30;
1118 break;
1119 case 0x7F00:
1120 x = 17 * threshold / 30;
1121 break;
1122 case 0x8000:
1123 x -= 17 * threshold / 30;
1124 break;
1125 }
1126 }
1127
1128 if (hits == 2 && msec_hit < timeout) {
1129 result = 0;
1130 hits = 1;
1131 }
1132 } else {
1133 prev_result = result;
1134 hits = 1;
1135 hit_time = ct;
1136 }
1137 }
1138
1139 return result;
1140}
1141
1142static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
1143{
1144 u32 keycode;
1145 u32 release;
1146 bool is_release_code = false;
1147
1148 /* Look for the initial press of a button */
1149 keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
1150 ictx->rc_toggle = 0x0;
1151 ictx->rc_scancode = scancode;
1152
1153 /* Look for the release of a button */
1154 if (keycode == KEY_RESERVED) {
1155 release = scancode & ~0x4000;
1156 keycode = rc_g_keycode_from_table(ictx->rdev, release);
1157 if (keycode != KEY_RESERVED)
1158 is_release_code = true;
1159 }
1160
1161 ictx->release_code = is_release_code;
1162
1163 return keycode;
1164}
1165
1166static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
1167{
1168 u32 keycode;
1169
1170#define MCE_KEY_MASK 0x7000
1171#define MCE_TOGGLE_BIT 0x8000
1172
1173 /*
1174 * On some receivers, mce keys decode to 0x8000f04xx and 0x8000f84xx
1175 * (the toggle bit flipping between alternating key presses), while
1176 * on other receivers, we see 0x8000f74xx and 0x8000ff4xx. To keep
1177 * the table trim, we always or in the bits to look up 0x8000ff4xx,
1178 * but we can't or them into all codes, as some keys are decoded in
1179 * a different way w/o the same use of the toggle bit...
1180 */
1181 if (scancode & 0x80000000)
1182 scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
1183
1184 ictx->rc_scancode = scancode;
1185 keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
1186
1187 /* not used in mce mode, but make sure we know its false */
1188 ictx->release_code = false;
1189
1190 return keycode;
1191}
1192
1193static u32 imon_panel_key_lookup(u64 code)
1194{
1195 int i;
1196 u32 keycode = KEY_RESERVED;
1197
1198 for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
1199 if (imon_panel_key_table[i].hw_code == (code | 0xffee)) {
1200 keycode = imon_panel_key_table[i].keycode;
1201 break;
1202 }
1203 }
1204
1205 return keycode;
1206}
1207
1208static bool imon_mouse_event(struct imon_context *ictx,
1209 unsigned char *buf, int len)
1210{
1211 char rel_x = 0x00, rel_y = 0x00;
1212 u8 right_shift = 1;
1213 bool mouse_input = true;
1214 int dir = 0;
1215 unsigned long flags;
1216
1217 spin_lock_irqsave(&ictx->kc_lock, flags);
1218
1219 /* newer iMON device PAD or mouse button */
1220 if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
1221 rel_x = buf[2];
1222 rel_y = buf[3];
1223 right_shift = 1;
1224 /* 0xffdc iMON PAD or mouse button input */
1225 } else if (ictx->product == 0xffdc && (buf[0] & 0x40) &&
1226 !((buf[1] & 0x01) || ((buf[1] >> 2) & 0x01))) {
1227 rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
1228 (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
1229 if (buf[0] & 0x02)
1230 rel_x |= ~0x0f;
1231 rel_x = rel_x + rel_x / 2;
1232 rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
1233 (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
1234 if (buf[0] & 0x01)
1235 rel_y |= ~0x0f;
1236 rel_y = rel_y + rel_y / 2;
1237 right_shift = 2;
1238 /* some ffdc devices decode mouse buttons differently... */
1239 } else if (ictx->product == 0xffdc && (buf[0] == 0x68)) {
1240 right_shift = 2;
1241 /* ch+/- buttons, which we use for an emulated scroll wheel */
1242 } else if (ictx->kc == KEY_CHANNELUP && (buf[2] & 0x40) != 0x40) {
1243 dir = 1;
1244 } else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
1245 dir = -1;
1246 } else
1247 mouse_input = false;
1248
1249 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1250
1251 if (mouse_input) {
1252 dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
1253
1254 if (dir) {
1255 input_report_rel(ictx->idev, REL_WHEEL, dir);
1256 } else if (rel_x || rel_y) {
1257 input_report_rel(ictx->idev, REL_X, rel_x);
1258 input_report_rel(ictx->idev, REL_Y, rel_y);
1259 } else {
1260 input_report_key(ictx->idev, BTN_LEFT, buf[1] & 0x1);
1261 input_report_key(ictx->idev, BTN_RIGHT,
1262 buf[1] >> right_shift & 0x1);
1263 }
1264 input_sync(ictx->idev);
1265 spin_lock_irqsave(&ictx->kc_lock, flags);
1266 ictx->last_keycode = ictx->kc;
1267 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1268 }
1269
1270 return mouse_input;
1271}
1272
1273static void imon_touch_event(struct imon_context *ictx, unsigned char *buf)
1274{
1275 mod_timer(&ictx->ttimer, jiffies + TOUCH_TIMEOUT);
1276 ictx->touch_x = (buf[0] << 4) | (buf[1] >> 4);
1277 ictx->touch_y = 0xfff - ((buf[2] << 4) | (buf[1] & 0xf));
1278 input_report_abs(ictx->touch, ABS_X, ictx->touch_x);
1279 input_report_abs(ictx->touch, ABS_Y, ictx->touch_y);
1280 input_report_key(ictx->touch, BTN_TOUCH, 0x01);
1281 input_sync(ictx->touch);
1282}
1283
1284static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
1285{
1286 int dir = 0;
1287 char rel_x = 0x00, rel_y = 0x00;
1288 u16 timeout, threshold;
1289 u32 scancode = KEY_RESERVED;
1290 unsigned long flags;
1291
1292 /*
1293 * The imon directional pad functions more like a touchpad. Bytes 3 & 4
1294 * contain a position coordinate (x,y), with each component ranging
1295 * from -14 to 14. We want to down-sample this to only 4 discrete values
1296 * for up/down/left/right arrow keys. Also, when you get too close to
1297 * diagonals, it has a tendancy to jump back and forth, so lets try to
1298 * ignore when they get too close.
1299 */
1300 if (ictx->product != 0xffdc) {
1301 /* first, pad to 8 bytes so it conforms with everything else */
1302 buf[5] = buf[6] = buf[7] = 0;
1303 timeout = 500; /* in msecs */
1304 /* (2*threshold) x (2*threshold) square */
1305 threshold = pad_thresh ? pad_thresh : 28;
1306 rel_x = buf[2];
1307 rel_y = buf[3];
1308
1309 if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
1310 if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
1311 dir = stabilize((int)rel_x, (int)rel_y,
1312 timeout, threshold);
1313 if (!dir) {
1314 spin_lock_irqsave(&ictx->kc_lock,
1315 flags);
1316 ictx->kc = KEY_UNKNOWN;
1317 spin_unlock_irqrestore(&ictx->kc_lock,
1318 flags);
1319 return;
1320 }
1321 buf[2] = dir & 0xFF;
1322 buf[3] = (dir >> 8) & 0xFF;
1323 scancode = be32_to_cpu(*((u32 *)buf));
1324 }
1325 } else {
1326 /*
1327 * Hack alert: instead of using keycodes, we have
1328 * to use hard-coded scancodes here...
1329 */
1330 if (abs(rel_y) > abs(rel_x)) {
1331 buf[2] = (rel_y > 0) ? 0x7F : 0x80;
1332 buf[3] = 0;
1333 if (rel_y > 0)
1334 scancode = 0x01007f00; /* KEY_DOWN */
1335 else
1336 scancode = 0x01008000; /* KEY_UP */
1337 } else {
1338 buf[2] = 0;
1339 buf[3] = (rel_x > 0) ? 0x7F : 0x80;
1340 if (rel_x > 0)
1341 scancode = 0x0100007f; /* KEY_RIGHT */
1342 else
1343 scancode = 0x01000080; /* KEY_LEFT */
1344 }
1345 }
1346
1347 /*
1348 * Handle on-board decoded pad events for e.g. older VFD/iMON-Pad
1349 * device (15c2:ffdc). The remote generates various codes from
1350 * 0x68nnnnB7 to 0x6AnnnnB7, the left mouse button generates
1351 * 0x688301b7 and the right one 0x688481b7. All other keys generate
1352 * 0x2nnnnnnn. Position coordinate is encoded in buf[1] and buf[2] with
1353 * reversed endianess. Extract direction from buffer, rotate endianess,
1354 * adjust sign and feed the values into stabilize(). The resulting codes
1355 * will be 0x01008000, 0x01007F00, which match the newer devices.
1356 */
1357 } else {
1358 timeout = 10; /* in msecs */
1359 /* (2*threshold) x (2*threshold) square */
1360 threshold = pad_thresh ? pad_thresh : 15;
1361
1362 /* buf[1] is x */
1363 rel_x = (buf[1] & 0x08) | (buf[1] & 0x10) >> 2 |
1364 (buf[1] & 0x20) >> 4 | (buf[1] & 0x40) >> 6;
1365 if (buf[0] & 0x02)
1366 rel_x |= ~0x10+1;
1367 /* buf[2] is y */
1368 rel_y = (buf[2] & 0x08) | (buf[2] & 0x10) >> 2 |
1369 (buf[2] & 0x20) >> 4 | (buf[2] & 0x40) >> 6;
1370 if (buf[0] & 0x01)
1371 rel_y |= ~0x10+1;
1372
1373 buf[0] = 0x01;
1374 buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
1375
1376 if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
1377 dir = stabilize((int)rel_x, (int)rel_y,
1378 timeout, threshold);
1379 if (!dir) {
1380 spin_lock_irqsave(&ictx->kc_lock, flags);
1381 ictx->kc = KEY_UNKNOWN;
1382 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1383 return;
1384 }
1385 buf[2] = dir & 0xFF;
1386 buf[3] = (dir >> 8) & 0xFF;
1387 scancode = be32_to_cpu(*((u32 *)buf));
1388 } else {
1389 /*
1390 * Hack alert: instead of using keycodes, we have
1391 * to use hard-coded scancodes here...
1392 */
1393 if (abs(rel_y) > abs(rel_x)) {
1394 buf[2] = (rel_y > 0) ? 0x7F : 0x80;
1395 buf[3] = 0;
1396 if (rel_y > 0)
1397 scancode = 0x01007f00; /* KEY_DOWN */
1398 else
1399 scancode = 0x01008000; /* KEY_UP */
1400 } else {
1401 buf[2] = 0;
1402 buf[3] = (rel_x > 0) ? 0x7F : 0x80;
1403 if (rel_x > 0)
1404 scancode = 0x0100007f; /* KEY_RIGHT */
1405 else
1406 scancode = 0x01000080; /* KEY_LEFT */
1407 }
1408 }
1409 }
1410
1411 if (scancode) {
1412 spin_lock_irqsave(&ictx->kc_lock, flags);
1413 ictx->kc = imon_remote_key_lookup(ictx, scancode);
1414 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1415 }
1416}
1417
1418/**
1419 * figure out if these is a press or a release. We don't actually
1420 * care about repeats, as those will be auto-generated within the IR
1421 * subsystem for repeating scancodes.
1422 */
1423static int imon_parse_press_type(struct imon_context *ictx,
1424 unsigned char *buf, u8 ktype)
1425{
1426 int press_type = 0;
1427 unsigned long flags;
1428
1429 spin_lock_irqsave(&ictx->kc_lock, flags);
1430
1431 /* key release of 0x02XXXXXX key */
1432 if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
1433 ictx->kc = ictx->last_keycode;
1434
1435 /* mouse button release on (some) 0xffdc devices */
1436 else if (ictx->kc == KEY_RESERVED && buf[0] == 0x68 && buf[1] == 0x82 &&
1437 buf[2] == 0x81 && buf[3] == 0xb7)
1438 ictx->kc = ictx->last_keycode;
1439
1440 /* mouse button release on (some other) 0xffdc devices */
1441 else if (ictx->kc == KEY_RESERVED && buf[0] == 0x01 && buf[1] == 0x00 &&
1442 buf[2] == 0x81 && buf[3] == 0xb7)
1443 ictx->kc = ictx->last_keycode;
1444
1445 /* mce-specific button handling, no keyup events */
1446 else if (ktype == IMON_KEY_MCE) {
1447 ictx->rc_toggle = buf[2];
1448 press_type = 1;
1449
1450 /* incoherent or irrelevant data */
1451 } else if (ictx->kc == KEY_RESERVED)
1452 press_type = -EINVAL;
1453
1454 /* key release of 0xXXXXXXb7 key */
1455 else if (ictx->release_code)
1456 press_type = 0;
1457
1458 /* this is a button press */
1459 else
1460 press_type = 1;
1461
1462 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1463
1464 return press_type;
1465}
1466
1467/**
1468 * Process the incoming packet
1469 */
1470static void imon_incoming_packet(struct imon_context *ictx,
1471 struct urb *urb, int intf)
1472{
1473 int len = urb->actual_length;
1474 unsigned char *buf = urb->transfer_buffer;
1475 struct device *dev = ictx->dev;
1476 unsigned long flags;
1477 u32 kc;
1478 bool norelease = false;
1479 int i;
1480 u64 scancode;
1481 int press_type = 0;
1482 int msec;
1483 struct timeval t;
1484 static struct timeval prev_time = { 0, 0 };
1485 u8 ktype;
1486
1487 /* filter out junk data on the older 0xffdc imon devices */
1488 if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
1489 return;
1490
1491 /* Figure out what key was pressed */
1492 if (len == 8 && buf[7] == 0xee) {
1493 scancode = be64_to_cpu(*((u64 *)buf));
1494 ktype = IMON_KEY_PANEL;
1495 kc = imon_panel_key_lookup(scancode);
1496 } else {
1497 scancode = be32_to_cpu(*((u32 *)buf));
1498 if (ictx->rc_type == RC_TYPE_RC6) {
1499 ktype = IMON_KEY_IMON;
1500 if (buf[0] == 0x80)
1501 ktype = IMON_KEY_MCE;
1502 kc = imon_mce_key_lookup(ictx, scancode);
1503 } else {
1504 ktype = IMON_KEY_IMON;
1505 kc = imon_remote_key_lookup(ictx, scancode);
1506 }
1507 }
1508
1509 spin_lock_irqsave(&ictx->kc_lock, flags);
1510 /* keyboard/mouse mode toggle button */
1511 if (kc == KEY_KEYBOARD && !ictx->release_code) {
1512 ictx->last_keycode = kc;
1513 if (!nomouse) {
1514 ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
1515 dev_dbg(dev, "toggling to %s mode\n",
1516 ictx->pad_mouse ? "mouse" : "keyboard");
1517 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1518 return;
1519 } else {
1520 ictx->pad_mouse = 0;
1521 dev_dbg(dev, "mouse mode disabled, passing key value\n");
1522 }
1523 }
1524
1525 ictx->kc = kc;
1526 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1527
1528 /* send touchscreen events through input subsystem if touchpad data */
1529 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
1530 buf[7] == 0x86) {
1531 imon_touch_event(ictx, buf);
1532 return;
1533
1534 /* look for mouse events with pad in mouse mode */
1535 } else if (ictx->pad_mouse) {
1536 if (imon_mouse_event(ictx, buf, len))
1537 return;
1538 }
1539
1540 /* Now for some special handling to convert pad input to arrow keys */
1541 if (((len == 5) && (buf[0] == 0x01) && (buf[4] == 0x00)) ||
1542 ((len == 8) && (buf[0] & 0x40) &&
1543 !(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
1544 len = 8;
1545 imon_pad_to_keys(ictx, buf);
1546 norelease = true;
1547 }
1548
1549 if (debug) {
1550 printk(KERN_INFO "intf%d decoded packet: ", intf);
1551 for (i = 0; i < len; ++i)
1552 printk("%02x ", buf[i]);
1553 printk("\n");
1554 }
1555
1556 press_type = imon_parse_press_type(ictx, buf, ktype);
1557 if (press_type < 0)
1558 goto not_input_data;
1559
1560 spin_lock_irqsave(&ictx->kc_lock, flags);
1561 if (ictx->kc == KEY_UNKNOWN)
1562 goto unknown_key;
1563 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1564
1565 if (ktype != IMON_KEY_PANEL) {
1566 if (press_type == 0)
1567 rc_keyup(ictx->rdev);
1568 else {
1569 rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle);
1570 spin_lock_irqsave(&ictx->kc_lock, flags);
1571 ictx->last_keycode = ictx->kc;
1572 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1573 }
1574 return;
1575 }
1576
1577 /* Only panel type events left to process now */
1578 spin_lock_irqsave(&ictx->kc_lock, flags);
1579
1580 /* KEY_MUTE repeats from knob need to be suppressed */
1581 if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
1582 do_gettimeofday(&t);
1583 msec = tv2int(&t, &prev_time);
1584 prev_time = t;
1585 if (msec < ictx->idev->rep[REP_DELAY]) {
1586 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1587 return;
1588 }
1589 }
1590 kc = ictx->kc;
1591
1592 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1593
1594 input_report_key(ictx->idev, kc, press_type);
1595 input_sync(ictx->idev);
1596
1597 /* panel keys don't generate a release */
1598 input_report_key(ictx->idev, kc, 0);
1599 input_sync(ictx->idev);
1600
1601 ictx->last_keycode = kc;
1602
1603 return;
1604
1605unknown_key:
1606 spin_unlock_irqrestore(&ictx->kc_lock, flags);
1607 dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
1608 (long long)scancode);
1609 return;
1610
1611not_input_data:
1612 if (len != 8) {
1613 dev_warn(dev, "imon %s: invalid incoming packet "
1614 "size (len = %d, intf%d)\n", __func__, len, intf);
1615 return;
1616 }
1617
1618 /* iMON 2.4G associate frame */
1619 if (buf[0] == 0x00 &&
1620 buf[2] == 0xFF && /* REFID */
1621 buf[3] == 0xFF &&
1622 buf[4] == 0xFF &&
1623 buf[5] == 0xFF && /* iMON 2.4G */
1624 ((buf[6] == 0x4E && buf[7] == 0xDF) || /* LT */
1625 (buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */
1626 dev_warn(dev, "%s: remote associated refid=%02X\n",
1627 __func__, buf[1]);
1628 ictx->rf_isassociating = false;
1629 }
1630}
1631
1632/**
1633 * Callback function for USB core API: receive data
1634 */
1635static void usb_rx_callback_intf0(struct urb *urb)
1636{
1637 struct imon_context *ictx;
1638 int intfnum = 0;
1639
1640 if (!urb)
1641 return;
1642
1643 ictx = (struct imon_context *)urb->context;
1644 if (!ictx)
1645 return;
1646
1647 switch (urb->status) {
1648 case -ENOENT: /* usbcore unlink successful! */
1649 return;
1650
1651 case -ESHUTDOWN: /* transport endpoint was shut down */
1652 break;
1653
1654 case 0:
1655 imon_incoming_packet(ictx, urb, intfnum);
1656 break;
1657
1658 default:
1659 dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
1660 __func__, urb->status);
1661 break;
1662 }
1663
1664 usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
1665}
1666
1667static void usb_rx_callback_intf1(struct urb *urb)
1668{
1669 struct imon_context *ictx;
1670 int intfnum = 1;
1671
1672 if (!urb)
1673 return;
1674
1675 ictx = (struct imon_context *)urb->context;
1676 if (!ictx)
1677 return;
1678
1679 switch (urb->status) {
1680 case -ENOENT: /* usbcore unlink successful! */
1681 return;
1682
1683 case -ESHUTDOWN: /* transport endpoint was shut down */
1684 break;
1685
1686 case 0:
1687 imon_incoming_packet(ictx, urb, intfnum);
1688 break;
1689
1690 default:
1691 dev_warn(ictx->dev, "imon %s: status(%d): ignored\n",
1692 __func__, urb->status);
1693 break;
1694 }
1695
1696 usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
1697}
1698
1699/*
1700 * The 0x15c2:0xffdc device ID was used for umpteen different imon
1701 * devices, and all of them constantly spew interrupts, even when there
1702 * is no actual data to report. However, byte 6 of this buffer looks like
1703 * its unique across device variants, so we're trying to key off that to
1704 * figure out which display type (if any) and what IR protocol the device
1705 * actually supports. These devices have their IR protocol hard-coded into
1706 * their firmware, they can't be changed on the fly like the newer hardware.
1707 */
1708static void imon_get_ffdc_type(struct imon_context *ictx)
1709{
1710 u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
1711 u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
1712 u64 allowed_protos = RC_TYPE_OTHER;
1713
1714 switch (ffdc_cfg_byte) {
1715 /* iMON Knob, no display, iMON IR + vol knob */
1716 case 0x21:
1717 dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
1718 ictx->display_supported = false;
1719 break;
1720 /* iMON 2.4G LT (usb stick), no display, iMON RF */
1721 case 0x4e:
1722 dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
1723 ictx->display_supported = false;
1724 ictx->rf_device = true;
1725 break;
1726 /* iMON VFD, no IR (does have vol knob tho) */
1727 case 0x35:
1728 dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
1729 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1730 break;
1731 /* iMON VFD, iMON IR */
1732 case 0x24:
1733 case 0x85:
1734 dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
1735 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1736 break;
1737 /* iMON VFD, MCE IR */
1738 case 0x9e:
1739 dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
1740 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1741 allowed_protos = RC_TYPE_RC6;
1742 break;
1743 /* iMON LCD, MCE IR */
1744 case 0x9f:
1745 dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
1746 detected_display_type = IMON_DISPLAY_TYPE_LCD;
1747 allowed_protos = RC_TYPE_RC6;
1748 break;
1749 default:
1750 dev_info(ictx->dev, "Unknown 0xffdc device, "
1751 "defaulting to VFD and iMON IR");
1752 detected_display_type = IMON_DISPLAY_TYPE_VFD;
1753 break;
1754 }
1755
1756 printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
1757
1758 ictx->display_type = detected_display_type;
1759 ictx->rdev->allowed_protos = allowed_protos;
1760 ictx->rc_type = allowed_protos;
1761}
1762
1763static void imon_set_display_type(struct imon_context *ictx)
1764{
1765 u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
1766
1767 /*
1768 * Try to auto-detect the type of display if the user hasn't set
1769 * it by hand via the display_type modparam. Default is VFD.
1770 */
1771
1772 if (display_type == IMON_DISPLAY_TYPE_AUTO) {
1773 switch (ictx->product) {
1774 case 0xffdc:
1775 /* set in imon_get_ffdc_type() */
1776 configured_display_type = ictx->display_type;
1777 break;
1778 case 0x0034:
1779 case 0x0035:
1780 configured_display_type = IMON_DISPLAY_TYPE_VGA;
1781 break;
1782 case 0x0038:
1783 case 0x0039:
1784 case 0x0045:
1785 configured_display_type = IMON_DISPLAY_TYPE_LCD;
1786 break;
1787 case 0x003c:
1788 case 0x0041:
1789 case 0x0042:
1790 case 0x0043:
1791 configured_display_type = IMON_DISPLAY_TYPE_NONE;
1792 ictx->display_supported = false;
1793 break;
1794 case 0x0036:
1795 case 0x0044:
1796 default:
1797 configured_display_type = IMON_DISPLAY_TYPE_VFD;
1798 break;
1799 }
1800 } else {
1801 configured_display_type = display_type;
1802 if (display_type == IMON_DISPLAY_TYPE_NONE)
1803 ictx->display_supported = false;
1804 else
1805 ictx->display_supported = true;
1806 dev_info(ictx->dev, "%s: overriding display type to %d via "
1807 "modparam\n", __func__, display_type);
1808 }
1809
1810 ictx->display_type = configured_display_type;
1811}
1812
1813static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
1814{
1815 struct rc_dev *rdev;
1816 int ret;
1817 const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
1818 0x00, 0x00, 0x00, 0x88 };
1819
1820 rdev = rc_allocate_device();
1821 if (!rdev) {
1822 dev_err(ictx->dev, "remote control dev allocation failed\n");
1823 goto out;
1824 }
1825
1826 snprintf(ictx->name_rdev, sizeof(ictx->name_rdev),
1827 "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
1828 usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev,
1829 sizeof(ictx->phys_rdev));
1830 strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev));
1831
1832 rdev->input_name = ictx->name_rdev;
1833 rdev->input_phys = ictx->phys_rdev;
1834 usb_to_input_id(ictx->usbdev_intf0, &rdev->input_id);
1835 rdev->dev.parent = ictx->dev;
1836
1837 rdev->priv = ictx;
1838 rdev->driver_type = RC_DRIVER_SCANCODE;
1839 rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */
1840 rdev->change_protocol = imon_ir_change_protocol;
1841 rdev->driver_name = MOD_NAME;
1842 if (ictx->rc_type == RC_TYPE_RC6)
1843 rdev->map_name = RC_MAP_IMON_MCE;
1844 else
1845 rdev->map_name = RC_MAP_IMON_PAD;
1846
1847 /* Enable front-panel buttons and/or knobs */
1848 memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
1849 ret = send_packet(ictx);
1850 /* Not fatal, but warn about it */
1851 if (ret)
1852 dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
1853
1854 if (ictx->product == 0xffdc)
1855 imon_get_ffdc_type(ictx);
1856
1857 imon_set_display_type(ictx);
1858
1859 ret = rc_register_device(rdev);
1860 if (ret < 0) {
1861 dev_err(ictx->dev, "remote input dev register failed\n");
1862 goto out;
1863 }
1864
1865 return rdev;
1866
1867out:
1868 rc_free_device(rdev);
1869 return NULL;
1870}
1871
1872static struct input_dev *imon_init_idev(struct imon_context *ictx)
1873{
1874 struct input_dev *idev;
1875 int ret, i;
1876
1877 idev = input_allocate_device();
1878 if (!idev) {
1879 dev_err(ictx->dev, "input dev allocation failed\n");
1880 goto out;
1881 }
1882
1883 snprintf(ictx->name_idev, sizeof(ictx->name_idev),
1884 "iMON Panel, Knob and Mouse(%04x:%04x)",
1885 ictx->vendor, ictx->product);
1886 idev->name = ictx->name_idev;
1887
1888 usb_make_path(ictx->usbdev_intf0, ictx->phys_idev,
1889 sizeof(ictx->phys_idev));
1890 strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev));
1891 idev->phys = ictx->phys_idev;
1892
1893 idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
1894
1895 idev->keybit[BIT_WORD(BTN_MOUSE)] =
1896 BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
1897 idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) |
1898 BIT_MASK(REL_WHEEL);
1899
1900 /* panel and/or knob code support */
1901 for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
1902 u32 kc = imon_panel_key_table[i].keycode;
1903 __set_bit(kc, idev->keybit);
1904 }
1905
1906 usb_to_input_id(ictx->usbdev_intf0, &idev->id);
1907 idev->dev.parent = ictx->dev;
1908 input_set_drvdata(idev, ictx);
1909
1910 ret = input_register_device(idev);
1911 if (ret < 0) {
1912 dev_err(ictx->dev, "input dev register failed\n");
1913 goto out;
1914 }
1915
1916 return idev;
1917
1918out:
1919 input_free_device(idev);
1920 return NULL;
1921}
1922
1923static struct input_dev *imon_init_touch(struct imon_context *ictx)
1924{
1925 struct input_dev *touch;
1926 int ret;
1927
1928 touch = input_allocate_device();
1929 if (!touch) {
1930 dev_err(ictx->dev, "touchscreen input dev allocation failed\n");
1931 goto touch_alloc_failed;
1932 }
1933
1934 snprintf(ictx->name_touch, sizeof(ictx->name_touch),
1935 "iMON USB Touchscreen (%04x:%04x)",
1936 ictx->vendor, ictx->product);
1937 touch->name = ictx->name_touch;
1938
1939 usb_make_path(ictx->usbdev_intf1, ictx->phys_touch,
1940 sizeof(ictx->phys_touch));
1941 strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch));
1942 touch->phys = ictx->phys_touch;
1943
1944 touch->evbit[0] =
1945 BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
1946 touch->keybit[BIT_WORD(BTN_TOUCH)] =
1947 BIT_MASK(BTN_TOUCH);
1948 input_set_abs_params(touch, ABS_X,
1949 0x00, 0xfff, 0, 0);
1950 input_set_abs_params(touch, ABS_Y,
1951 0x00, 0xfff, 0, 0);
1952
1953 input_set_drvdata(touch, ictx);
1954
1955 usb_to_input_id(ictx->usbdev_intf1, &touch->id);
1956 touch->dev.parent = ictx->dev;
1957 ret = input_register_device(touch);
1958 if (ret < 0) {
1959 dev_info(ictx->dev, "touchscreen input dev register failed\n");
1960 goto touch_register_failed;
1961 }
1962
1963 return touch;
1964
1965touch_register_failed:
1966 input_free_device(ictx->touch);
1967
1968touch_alloc_failed:
1969 return NULL;
1970}
1971
1972static bool imon_find_endpoints(struct imon_context *ictx,
1973 struct usb_host_interface *iface_desc)
1974{
1975 struct usb_endpoint_descriptor *ep;
1976 struct usb_endpoint_descriptor *rx_endpoint = NULL;
1977 struct usb_endpoint_descriptor *tx_endpoint = NULL;
1978 int ifnum = iface_desc->desc.bInterfaceNumber;
1979 int num_endpts = iface_desc->desc.bNumEndpoints;
1980 int i, ep_dir, ep_type;
1981 bool ir_ep_found = false;
1982 bool display_ep_found = false;
1983 bool tx_control = false;
1984
1985 /*
1986 * Scan the endpoint list and set:
1987 * first input endpoint = IR endpoint
1988 * first output endpoint = display endpoint
1989 */
1990 for (i = 0; i < num_endpts && !(ir_ep_found && display_ep_found); ++i) {
1991 ep = &iface_desc->endpoint[i].desc;
1992 ep_dir = ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK;
1993 ep_type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
1994
1995 if (!ir_ep_found && ep_dir == USB_DIR_IN &&
1996 ep_type == USB_ENDPOINT_XFER_INT) {
1997
1998 rx_endpoint = ep;
1999 ir_ep_found = true;
2000 dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
2001
2002 } else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
2003 ep_type == USB_ENDPOINT_XFER_INT) {
2004 tx_endpoint = ep;
2005 display_ep_found = true;
2006 dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
2007 }
2008 }
2009
2010 if (ifnum == 0) {
2011 ictx->rx_endpoint_intf0 = rx_endpoint;
2012 /*
2013 * tx is used to send characters to lcd/vfd, associate RF
2014 * remotes, set IR protocol, and maybe more...
2015 */
2016 ictx->tx_endpoint = tx_endpoint;
2017 } else {
2018 ictx->rx_endpoint_intf1 = rx_endpoint;
2019 }
2020
2021 /*
2022 * If we didn't find a display endpoint, this is probably one of the
2023 * newer iMON devices that use control urb instead of interrupt
2024 */
2025 if (!display_ep_found) {
2026 tx_control = true;
2027 display_ep_found = true;
2028 dev_dbg(ictx->dev, "%s: device uses control endpoint, not "
2029 "interface OUT endpoint\n", __func__);
2030 }
2031
2032 /*
2033 * Some iMON receivers have no display. Unfortunately, it seems
2034 * that SoundGraph recycles device IDs between devices both with
2035 * and without... :\
2036 */
2037 if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
2038 display_ep_found = false;
2039 dev_dbg(ictx->dev, "%s: device has no display\n", __func__);
2040 }
2041
2042 /*
2043 * iMON Touch devices have a VGA touchscreen, but no "display", as
2044 * that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
2045 */
2046 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
2047 display_ep_found = false;
2048 dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__);
2049 }
2050
2051 /* Input endpoint is mandatory */
2052 if (!ir_ep_found)
2053 pr_err("no valid input (IR) endpoint found\n");
2054
2055 ictx->tx_control = tx_control;
2056
2057 if (display_ep_found)
2058 ictx->display_supported = true;
2059
2060 return ir_ep_found;
2061
2062}
2063
2064static struct imon_context *imon_init_intf0(struct usb_interface *intf)
2065{
2066 struct imon_context *ictx;
2067 struct urb *rx_urb;
2068 struct urb *tx_urb;
2069 struct device *dev = &intf->dev;
2070 struct usb_host_interface *iface_desc;
2071 int ret = -ENOMEM;
2072
2073 ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
2074 if (!ictx) {
2075 dev_err(dev, "%s: kzalloc failed for context", __func__);
2076 goto exit;
2077 }
2078 rx_urb = usb_alloc_urb(0, GFP_KERNEL);
2079 if (!rx_urb) {
2080 dev_err(dev, "%s: usb_alloc_urb failed for IR urb", __func__);
2081 goto rx_urb_alloc_failed;
2082 }
2083 tx_urb = usb_alloc_urb(0, GFP_KERNEL);
2084 if (!tx_urb) {
2085 dev_err(dev, "%s: usb_alloc_urb failed for display urb",
2086 __func__);
2087 goto tx_urb_alloc_failed;
2088 }
2089
2090 mutex_init(&ictx->lock);
2091 spin_lock_init(&ictx->kc_lock);
2092
2093 mutex_lock(&ictx->lock);
2094
2095 ictx->dev = dev;
2096 ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
2097 ictx->dev_present_intf0 = true;
2098 ictx->rx_urb_intf0 = rx_urb;
2099 ictx->tx_urb = tx_urb;
2100 ictx->rf_device = false;
2101
2102 ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
2103 ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
2104
2105 ret = -ENODEV;
2106 iface_desc = intf->cur_altsetting;
2107 if (!imon_find_endpoints(ictx, iface_desc)) {
2108 goto find_endpoint_failed;
2109 }
2110
2111 ictx->idev = imon_init_idev(ictx);
2112 if (!ictx->idev) {
2113 dev_err(dev, "%s: input device setup failed\n", __func__);
2114 goto idev_setup_failed;
2115 }
2116
2117 ictx->rdev = imon_init_rdev(ictx);
2118 if (!ictx->rdev) {
2119 dev_err(dev, "%s: rc device setup failed\n", __func__);
2120 goto rdev_setup_failed;
2121 }
2122
2123 usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
2124 usb_rcvintpipe(ictx->usbdev_intf0,
2125 ictx->rx_endpoint_intf0->bEndpointAddress),
2126 ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
2127 usb_rx_callback_intf0, ictx,
2128 ictx->rx_endpoint_intf0->bInterval);
2129
2130 ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
2131 if (ret) {
2132 pr_err("usb_submit_urb failed for intf0 (%d)\n", ret);
2133 goto urb_submit_failed;
2134 }
2135
2136 return ictx;
2137
2138urb_submit_failed:
2139 rc_unregister_device(ictx->rdev);
2140rdev_setup_failed:
2141 input_unregister_device(ictx->idev);
2142idev_setup_failed:
2143find_endpoint_failed:
2144 mutex_unlock(&ictx->lock);
2145 usb_free_urb(tx_urb);
2146tx_urb_alloc_failed:
2147 usb_free_urb(rx_urb);
2148rx_urb_alloc_failed:
2149 kfree(ictx);
2150exit:
2151 dev_err(dev, "unable to initialize intf0, err %d\n", ret);
2152
2153 return NULL;
2154}
2155
2156static struct imon_context *imon_init_intf1(struct usb_interface *intf,
2157 struct imon_context *ictx)
2158{
2159 struct urb *rx_urb;
2160 struct usb_host_interface *iface_desc;
2161 int ret = -ENOMEM;
2162
2163 rx_urb = usb_alloc_urb(0, GFP_KERNEL);
2164 if (!rx_urb) {
2165 pr_err("usb_alloc_urb failed for IR urb\n");
2166 goto rx_urb_alloc_failed;
2167 }
2168
2169 mutex_lock(&ictx->lock);
2170
2171 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
2172 init_timer(&ictx->ttimer);
2173 ictx->ttimer.data = (unsigned long)ictx;
2174 ictx->ttimer.function = imon_touch_display_timeout;
2175 }
2176
2177 ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
2178 ictx->dev_present_intf1 = true;
2179 ictx->rx_urb_intf1 = rx_urb;
2180
2181 ret = -ENODEV;
2182 iface_desc = intf->cur_altsetting;
2183 if (!imon_find_endpoints(ictx, iface_desc))
2184 goto find_endpoint_failed;
2185
2186 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
2187 ictx->touch = imon_init_touch(ictx);
2188 if (!ictx->touch)
2189 goto touch_setup_failed;
2190 } else
2191 ictx->touch = NULL;
2192
2193 usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
2194 usb_rcvintpipe(ictx->usbdev_intf1,
2195 ictx->rx_endpoint_intf1->bEndpointAddress),
2196 ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
2197 usb_rx_callback_intf1, ictx,
2198 ictx->rx_endpoint_intf1->bInterval);
2199
2200 ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
2201
2202 if (ret) {
2203 pr_err("usb_submit_urb failed for intf1 (%d)\n", ret);
2204 goto urb_submit_failed;
2205 }
2206
2207 return ictx;
2208
2209urb_submit_failed:
2210 if (ictx->touch)
2211 input_unregister_device(ictx->touch);
2212touch_setup_failed:
2213find_endpoint_failed:
2214 mutex_unlock(&ictx->lock);
2215 usb_free_urb(rx_urb);
2216rx_urb_alloc_failed:
2217 dev_err(ictx->dev, "unable to initialize intf0, err %d\n", ret);
2218
2219 return NULL;
2220}
2221
2222static void imon_init_display(struct imon_context *ictx,
2223 struct usb_interface *intf)
2224{
2225 int ret;
2226
2227 dev_dbg(ictx->dev, "Registering iMON display with sysfs\n");
2228
2229 /* set up sysfs entry for built-in clock */
2230 ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group);
2231 if (ret)
2232 dev_err(ictx->dev, "Could not create display sysfs "
2233 "entries(%d)", ret);
2234
2235 if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
2236 ret = usb_register_dev(intf, &imon_lcd_class);
2237 else
2238 ret = usb_register_dev(intf, &imon_vfd_class);
2239 if (ret)
2240 /* Not a fatal error, so ignore */
2241 dev_info(ictx->dev, "could not get a minor number for "
2242 "display\n");
2243
2244}
2245
2246/**
2247 * Callback function for USB core API: Probe
2248 */
2249static int __devinit imon_probe(struct usb_interface *interface,
2250 const struct usb_device_id *id)
2251{
2252 struct usb_device *usbdev = NULL;
2253 struct usb_host_interface *iface_desc = NULL;
2254 struct usb_interface *first_if;
2255 struct device *dev = &interface->dev;
2256 int ifnum, code_length, sysfs_err;
2257 int ret = 0;
2258 struct imon_context *ictx = NULL;
2259 struct imon_context *first_if_ctx = NULL;
2260 u16 vendor, product;
2261
2262 code_length = BUF_CHUNK_SIZE * 8;
2263
2264 usbdev = usb_get_dev(interface_to_usbdev(interface));
2265 iface_desc = interface->cur_altsetting;
2266 ifnum = iface_desc->desc.bInterfaceNumber;
2267 vendor = le16_to_cpu(usbdev->descriptor.idVendor);
2268 product = le16_to_cpu(usbdev->descriptor.idProduct);
2269
2270 dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n",
2271 __func__, vendor, product, ifnum);
2272
2273 /* prevent races probing devices w/multiple interfaces */
2274 mutex_lock(&driver_lock);
2275
2276 first_if = usb_ifnum_to_if(usbdev, 0);
2277 first_if_ctx = usb_get_intfdata(first_if);
2278
2279 if (ifnum == 0) {
2280 ictx = imon_init_intf0(interface);
2281 if (!ictx) {
2282 pr_err("failed to initialize context!\n");
2283 ret = -ENODEV;
2284 goto fail;
2285 }
2286
2287 } else {
2288 /* this is the secondary interface on the device */
2289 ictx = imon_init_intf1(interface, first_if_ctx);
2290 if (!ictx) {
2291 pr_err("failed to attach to context!\n");
2292 ret = -ENODEV;
2293 goto fail;
2294 }
2295
2296 }
2297
2298 usb_set_intfdata(interface, ictx);
2299
2300 if (ifnum == 0) {
2301 if (product == 0xffdc && ictx->rf_device) {
2302 sysfs_err = sysfs_create_group(&interface->dev.kobj,
2303 &imon_rf_attr_group);
2304 if (sysfs_err)
2305 pr_err("Could not create RF sysfs entries(%d)\n",
2306 sysfs_err);
2307 }
2308
2309 if (ictx->display_supported)
2310 imon_init_display(ictx, interface);
2311 }
2312
2313 dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
2314 "usb<%d:%d> initialized\n", vendor, product, ifnum,
2315 usbdev->bus->busnum, usbdev->devnum);
2316
2317 mutex_unlock(&ictx->lock);
2318 mutex_unlock(&driver_lock);
2319
2320 return 0;
2321
2322fail:
2323 mutex_unlock(&driver_lock);
2324 dev_err(dev, "unable to register, err %d\n", ret);
2325
2326 return ret;
2327}
2328
2329/**
2330 * Callback function for USB core API: disconnect
2331 */
2332static void __devexit imon_disconnect(struct usb_interface *interface)
2333{
2334 struct imon_context *ictx;
2335 struct device *dev;
2336 int ifnum;
2337
2338 /* prevent races with multi-interface device probing and display_open */
2339 mutex_lock(&driver_lock);
2340
2341 ictx = usb_get_intfdata(interface);
2342 dev = ictx->dev;
2343 ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
2344
2345 mutex_lock(&ictx->lock);
2346
2347 /*
2348 * sysfs_remove_group is safe to call even if sysfs_create_group
2349 * hasn't been called
2350 */
2351 sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group);
2352 sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group);
2353
2354 usb_set_intfdata(interface, NULL);
2355
2356 /* Abort ongoing write */
2357 if (ictx->tx.busy) {
2358 usb_kill_urb(ictx->tx_urb);
2359 complete_all(&ictx->tx.finished);
2360 }
2361
2362 if (ifnum == 0) {
2363 ictx->dev_present_intf0 = false;
2364 usb_kill_urb(ictx->rx_urb_intf0);
2365 input_unregister_device(ictx->idev);
2366 rc_unregister_device(ictx->rdev);
2367 if (ictx->display_supported) {
2368 if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
2369 usb_deregister_dev(interface, &imon_lcd_class);
2370 else
2371 usb_deregister_dev(interface, &imon_vfd_class);
2372 }
2373 } else {
2374 ictx->dev_present_intf1 = false;
2375 usb_kill_urb(ictx->rx_urb_intf1);
2376 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
2377 input_unregister_device(ictx->touch);
2378 }
2379
2380 if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) {
2381 if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
2382 del_timer_sync(&ictx->ttimer);
2383 mutex_unlock(&ictx->lock);
2384 if (!ictx->display_isopen)
2385 free_imon_context(ictx);
2386 } else
2387 mutex_unlock(&ictx->lock);
2388
2389 mutex_unlock(&driver_lock);
2390
2391 dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n",
2392 __func__, ifnum);
2393}
2394
2395static int imon_suspend(struct usb_interface *intf, pm_message_t message)
2396{
2397 struct imon_context *ictx = usb_get_intfdata(intf);
2398 int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
2399
2400 if (ifnum == 0)
2401 usb_kill_urb(ictx->rx_urb_intf0);
2402 else
2403 usb_kill_urb(ictx->rx_urb_intf1);
2404
2405 return 0;
2406}
2407
2408static int imon_resume(struct usb_interface *intf)
2409{
2410 int rc = 0;
2411 struct imon_context *ictx = usb_get_intfdata(intf);
2412 int ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
2413
2414 if (ifnum == 0) {
2415 usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
2416 usb_rcvintpipe(ictx->usbdev_intf0,
2417 ictx->rx_endpoint_intf0->bEndpointAddress),
2418 ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
2419 usb_rx_callback_intf0, ictx,
2420 ictx->rx_endpoint_intf0->bInterval);
2421
2422 rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC);
2423
2424 } else {
2425 usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1,
2426 usb_rcvintpipe(ictx->usbdev_intf1,
2427 ictx->rx_endpoint_intf1->bEndpointAddress),
2428 ictx->usb_rx_buf, sizeof(ictx->usb_rx_buf),
2429 usb_rx_callback_intf1, ictx,
2430 ictx->rx_endpoint_intf1->bInterval);
2431
2432 rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
2433 }
2434
2435 return rc;
2436}
2437
2438static int __init imon_init(void)
2439{
2440 int rc;
2441
2442 rc = usb_register(&imon_driver);
2443 if (rc) {
2444 pr_err("usb register failed(%d)\n", rc);
2445 rc = -ENODEV;
2446 }
2447
2448 return rc;
2449}
2450
2451static void __exit imon_exit(void)
2452{
2453 usb_deregister(&imon_driver);
2454}
2455
2456module_init(imon_init);
2457module_exit(imon_exit);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
new file mode 100644
index 000000000000..624449afaa61
--- /dev/null
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -0,0 +1,198 @@
1/* ir-jvc-decoder.c - handle JVC IR Pulse/Space protocol
2 *
3 * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/bitrev.h>
16#include "rc-core-priv.h"
17
18#define JVC_NBITS 16 /* dev(8) + func(8) */
19#define JVC_UNIT 525000 /* ns */
20#define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */
21#define JVC_HEADER_SPACE (8 * JVC_UNIT)
22#define JVC_BIT_PULSE (1 * JVC_UNIT)
23#define JVC_BIT_0_SPACE (1 * JVC_UNIT)
24#define JVC_BIT_1_SPACE (3 * JVC_UNIT)
25#define JVC_TRAILER_PULSE (1 * JVC_UNIT)
26#define JVC_TRAILER_SPACE (35 * JVC_UNIT)
27
28enum jvc_state {
29 STATE_INACTIVE,
30 STATE_HEADER_SPACE,
31 STATE_BIT_PULSE,
32 STATE_BIT_SPACE,
33 STATE_TRAILER_PULSE,
34 STATE_TRAILER_SPACE,
35 STATE_CHECK_REPEAT,
36};
37
38/**
39 * ir_jvc_decode() - Decode one JVC pulse or space
40 * @dev: the struct rc_dev descriptor of the device
41 * @duration: the struct ir_raw_event descriptor of the pulse/space
42 *
43 * This function returns -EINVAL if the pulse violates the state machine
44 */
45static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
46{
47 struct jvc_dec *data = &dev->raw->jvc;
48
49 if (!(dev->raw->enabled_protocols & RC_TYPE_JVC))
50 return 0;
51
52 if (!is_timing_event(ev)) {
53 if (ev.reset)
54 data->state = STATE_INACTIVE;
55 return 0;
56 }
57
58 if (!geq_margin(ev.duration, JVC_UNIT, JVC_UNIT / 2))
59 goto out;
60
61 IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
62 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
63
64again:
65 switch (data->state) {
66
67 case STATE_INACTIVE:
68 if (!ev.pulse)
69 break;
70
71 if (!eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
72 break;
73
74 data->count = 0;
75 data->first = true;
76 data->toggle = !data->toggle;
77 data->state = STATE_HEADER_SPACE;
78 return 0;
79
80 case STATE_HEADER_SPACE:
81 if (ev.pulse)
82 break;
83
84 if (!eq_margin(ev.duration, JVC_HEADER_SPACE, JVC_UNIT / 2))
85 break;
86
87 data->state = STATE_BIT_PULSE;
88 return 0;
89
90 case STATE_BIT_PULSE:
91 if (!ev.pulse)
92 break;
93
94 if (!eq_margin(ev.duration, JVC_BIT_PULSE, JVC_UNIT / 2))
95 break;
96
97 data->state = STATE_BIT_SPACE;
98 return 0;
99
100 case STATE_BIT_SPACE:
101 if (ev.pulse)
102 break;
103
104 data->bits <<= 1;
105 if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
106 data->bits |= 1;
107 decrease_duration(&ev, JVC_BIT_1_SPACE);
108 } else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
109 decrease_duration(&ev, JVC_BIT_0_SPACE);
110 else
111 break;
112 data->count++;
113
114 if (data->count == JVC_NBITS)
115 data->state = STATE_TRAILER_PULSE;
116 else
117 data->state = STATE_BIT_PULSE;
118 return 0;
119
120 case STATE_TRAILER_PULSE:
121 if (!ev.pulse)
122 break;
123
124 if (!eq_margin(ev.duration, JVC_TRAILER_PULSE, JVC_UNIT / 2))
125 break;
126
127 data->state = STATE_TRAILER_SPACE;
128 return 0;
129
130 case STATE_TRAILER_SPACE:
131 if (ev.pulse)
132 break;
133
134 if (!geq_margin(ev.duration, JVC_TRAILER_SPACE, JVC_UNIT / 2))
135 break;
136
137 if (data->first) {
138 u32 scancode;
139 scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
140 (bitrev8((data->bits >> 0) & 0xff) << 0);
141 IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
142 rc_keydown(dev, scancode, data->toggle);
143 data->first = false;
144 data->old_bits = data->bits;
145 } else if (data->bits == data->old_bits) {
146 IR_dprintk(1, "JVC repeat\n");
147 rc_repeat(dev);
148 } else {
149 IR_dprintk(1, "JVC invalid repeat msg\n");
150 break;
151 }
152
153 data->count = 0;
154 data->state = STATE_CHECK_REPEAT;
155 return 0;
156
157 case STATE_CHECK_REPEAT:
158 if (!ev.pulse)
159 break;
160
161 if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
162 data->state = STATE_INACTIVE;
163 else
164 data->state = STATE_BIT_PULSE;
165 goto again;
166 }
167
168out:
169 IR_dprintk(1, "JVC decode failed at state %d (%uus %s)\n",
170 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
171 data->state = STATE_INACTIVE;
172 return -EINVAL;
173}
174
175static struct ir_raw_handler jvc_handler = {
176 .protocols = RC_TYPE_JVC,
177 .decode = ir_jvc_decode,
178};
179
180static int __init ir_jvc_decode_init(void)
181{
182 ir_raw_handler_register(&jvc_handler);
183
184 printk(KERN_INFO "IR JVC protocol handler initialized\n");
185 return 0;
186}
187
188static void __exit ir_jvc_decode_exit(void)
189{
190 ir_raw_handler_unregister(&jvc_handler);
191}
192
193module_init(ir_jvc_decode_init);
194module_exit(ir_jvc_decode_exit);
195
196MODULE_LICENSE("GPL");
197MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
198MODULE_DESCRIPTION("JVC IR protocol decoder");
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
new file mode 100644
index 000000000000..f011c5d9dea1
--- /dev/null
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -0,0 +1,402 @@
1/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
2 *
3 * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/sched.h>
16#include <linux/wait.h>
17#include <media/lirc.h>
18#include <media/lirc_dev.h>
19#include <media/rc-core.h>
20#include "rc-core-priv.h"
21
22#define LIRCBUF_SIZE 256
23
24/**
25 * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
26 * lircd userspace daemon for decoding.
27 * @input_dev: the struct rc_dev descriptor of the device
28 * @duration: the struct ir_raw_event descriptor of the pulse/space
29 *
30 * This function returns -EINVAL if the lirc interfaces aren't wired up.
31 */
32static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
33{
34 struct lirc_codec *lirc = &dev->raw->lirc;
35 int sample;
36
37 if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC))
38 return 0;
39
40 if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
41 return -EINVAL;
42
43 /* Packet start */
44 if (ev.reset)
45 return 0;
46
47 /* Carrier reports */
48 if (ev.carrier_report) {
49 sample = LIRC_FREQUENCY(ev.carrier);
50
51 /* Packet end */
52 } else if (ev.timeout) {
53
54 if (lirc->gap)
55 return 0;
56
57 lirc->gap_start = ktime_get();
58 lirc->gap = true;
59 lirc->gap_duration = ev.duration;
60
61 if (!lirc->send_timeout_reports)
62 return 0;
63
64 sample = LIRC_TIMEOUT(ev.duration / 1000);
65
66 /* Normal sample */
67 } else {
68
69 if (lirc->gap) {
70 int gap_sample;
71
72 lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
73 lirc->gap_start));
74
75 /* Convert to ms and cap by LIRC_VALUE_MASK */
76 do_div(lirc->gap_duration, 1000);
77 lirc->gap_duration = min(lirc->gap_duration,
78 (u64)LIRC_VALUE_MASK);
79
80 gap_sample = LIRC_SPACE(lirc->gap_duration);
81 lirc_buffer_write(dev->raw->lirc.drv->rbuf,
82 (unsigned char *) &gap_sample);
83 lirc->gap = false;
84 }
85
86 sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
87 LIRC_SPACE(ev.duration / 1000);
88 }
89
90 lirc_buffer_write(dev->raw->lirc.drv->rbuf,
91 (unsigned char *) &sample);
92 wake_up(&dev->raw->lirc.drv->rbuf->wait_poll);
93
94 return 0;
95}
96
97static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
98 size_t n, loff_t *ppos)
99{
100 struct lirc_codec *lirc;
101 struct rc_dev *dev;
102 int *txbuf; /* buffer with values to transmit */
103 int ret = 0;
104 size_t count;
105
106 lirc = lirc_get_pdata(file);
107 if (!lirc)
108 return -EFAULT;
109
110 if (n % sizeof(int))
111 return -EINVAL;
112
113 count = n / sizeof(int);
114 if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0)
115 return -EINVAL;
116
117 txbuf = memdup_user(buf, n);
118 if (IS_ERR(txbuf))
119 return PTR_ERR(txbuf);
120
121 dev = lirc->dev;
122 if (!dev) {
123 ret = -EFAULT;
124 goto out;
125 }
126
127 if (dev->tx_ir)
128 ret = dev->tx_ir(dev, txbuf, (u32)n);
129
130out:
131 kfree(txbuf);
132 return ret;
133}
134
135static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
136 unsigned long __user arg)
137{
138 struct lirc_codec *lirc;
139 struct rc_dev *dev;
140 int ret = 0;
141 __u32 val = 0, tmp;
142
143 lirc = lirc_get_pdata(filep);
144 if (!lirc)
145 return -EFAULT;
146
147 dev = lirc->dev;
148 if (!dev)
149 return -EFAULT;
150
151 if (_IOC_DIR(cmd) & _IOC_WRITE) {
152 ret = get_user(val, (__u32 *)arg);
153 if (ret)
154 return ret;
155 }
156
157 switch (cmd) {
158
159 /* legacy support */
160 case LIRC_GET_SEND_MODE:
161 val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
162 break;
163
164 case LIRC_SET_SEND_MODE:
165 if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
166 return -EINVAL;
167 return 0;
168
169 /* TX settings */
170 case LIRC_SET_TRANSMITTER_MASK:
171 if (!dev->s_tx_mask)
172 return -EINVAL;
173
174 return dev->s_tx_mask(dev, val);
175
176 case LIRC_SET_SEND_CARRIER:
177 if (!dev->s_tx_carrier)
178 return -EINVAL;
179
180 return dev->s_tx_carrier(dev, val);
181
182 case LIRC_SET_SEND_DUTY_CYCLE:
183 if (!dev->s_tx_duty_cycle)
184 return -ENOSYS;
185
186 if (val <= 0 || val >= 100)
187 return -EINVAL;
188
189 return dev->s_tx_duty_cycle(dev, val);
190
191 /* RX settings */
192 case LIRC_SET_REC_CARRIER:
193 if (!dev->s_rx_carrier_range)
194 return -ENOSYS;
195
196 if (val <= 0)
197 return -EINVAL;
198
199 return dev->s_rx_carrier_range(dev,
200 dev->raw->lirc.carrier_low,
201 val);
202
203 case LIRC_SET_REC_CARRIER_RANGE:
204 if (val <= 0)
205 return -EINVAL;
206
207 dev->raw->lirc.carrier_low = val;
208 return 0;
209
210 case LIRC_GET_REC_RESOLUTION:
211 val = dev->rx_resolution;
212 break;
213
214 case LIRC_SET_WIDEBAND_RECEIVER:
215 if (!dev->s_learning_mode)
216 return -ENOSYS;
217
218 return dev->s_learning_mode(dev, !!val);
219
220 case LIRC_SET_MEASURE_CARRIER_MODE:
221 if (!dev->s_carrier_report)
222 return -ENOSYS;
223
224 return dev->s_carrier_report(dev, !!val);
225
226 /* Generic timeout support */
227 case LIRC_GET_MIN_TIMEOUT:
228 if (!dev->max_timeout)
229 return -ENOSYS;
230 val = dev->min_timeout / 1000;
231 break;
232
233 case LIRC_GET_MAX_TIMEOUT:
234 if (!dev->max_timeout)
235 return -ENOSYS;
236 val = dev->max_timeout / 1000;
237 break;
238
239 case LIRC_SET_REC_TIMEOUT:
240 if (!dev->max_timeout)
241 return -ENOSYS;
242
243 tmp = val * 1000;
244
245 if (tmp < dev->min_timeout ||
246 tmp > dev->max_timeout)
247 return -EINVAL;
248
249 dev->timeout = tmp;
250 break;
251
252 case LIRC_SET_REC_TIMEOUT_REPORTS:
253 lirc->send_timeout_reports = !!val;
254 break;
255
256 default:
257 return lirc_dev_fop_ioctl(filep, cmd, arg);
258 }
259
260 if (_IOC_DIR(cmd) & _IOC_READ)
261 ret = put_user(val, (__u32 *)arg);
262
263 return ret;
264}
265
266static int ir_lirc_open(void *data)
267{
268 return 0;
269}
270
271static void ir_lirc_close(void *data)
272{
273 return;
274}
275
276static struct file_operations lirc_fops = {
277 .owner = THIS_MODULE,
278 .write = ir_lirc_transmit_ir,
279 .unlocked_ioctl = ir_lirc_ioctl,
280#ifdef CONFIG_COMPAT
281 .compat_ioctl = ir_lirc_ioctl,
282#endif
283 .read = lirc_dev_fop_read,
284 .poll = lirc_dev_fop_poll,
285 .open = lirc_dev_fop_open,
286 .release = lirc_dev_fop_close,
287 .llseek = no_llseek,
288};
289
290static int ir_lirc_register(struct rc_dev *dev)
291{
292 struct lirc_driver *drv;
293 struct lirc_buffer *rbuf;
294 int rc = -ENOMEM;
295 unsigned long features;
296
297 drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
298 if (!drv)
299 return rc;
300
301 rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
302 if (!rbuf)
303 goto rbuf_alloc_failed;
304
305 rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
306 if (rc)
307 goto rbuf_init_failed;
308
309 features = LIRC_CAN_REC_MODE2;
310 if (dev->tx_ir) {
311 features |= LIRC_CAN_SEND_PULSE;
312 if (dev->s_tx_mask)
313 features |= LIRC_CAN_SET_TRANSMITTER_MASK;
314 if (dev->s_tx_carrier)
315 features |= LIRC_CAN_SET_SEND_CARRIER;
316 if (dev->s_tx_duty_cycle)
317 features |= LIRC_CAN_SET_SEND_DUTY_CYCLE;
318 }
319
320 if (dev->s_rx_carrier_range)
321 features |= LIRC_CAN_SET_REC_CARRIER |
322 LIRC_CAN_SET_REC_CARRIER_RANGE;
323
324 if (dev->s_learning_mode)
325 features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
326
327 if (dev->s_carrier_report)
328 features |= LIRC_CAN_MEASURE_CARRIER;
329
330 if (dev->max_timeout)
331 features |= LIRC_CAN_SET_REC_TIMEOUT;
332
333 snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
334 dev->driver_name);
335 drv->minor = -1;
336 drv->features = features;
337 drv->data = &dev->raw->lirc;
338 drv->rbuf = rbuf;
339 drv->set_use_inc = &ir_lirc_open;
340 drv->set_use_dec = &ir_lirc_close;
341 drv->code_length = sizeof(struct ir_raw_event) * 8;
342 drv->fops = &lirc_fops;
343 drv->dev = &dev->dev;
344 drv->owner = THIS_MODULE;
345
346 drv->minor = lirc_register_driver(drv);
347 if (drv->minor < 0) {
348 rc = -ENODEV;
349 goto lirc_register_failed;
350 }
351
352 dev->raw->lirc.drv = drv;
353 dev->raw->lirc.dev = dev;
354 return 0;
355
356lirc_register_failed:
357rbuf_init_failed:
358 kfree(rbuf);
359rbuf_alloc_failed:
360 kfree(drv);
361
362 return rc;
363}
364
365static int ir_lirc_unregister(struct rc_dev *dev)
366{
367 struct lirc_codec *lirc = &dev->raw->lirc;
368
369 lirc_unregister_driver(lirc->drv->minor);
370 lirc_buffer_free(lirc->drv->rbuf);
371 kfree(lirc->drv);
372
373 return 0;
374}
375
376static struct ir_raw_handler lirc_handler = {
377 .protocols = RC_TYPE_LIRC,
378 .decode = ir_lirc_decode,
379 .raw_register = ir_lirc_register,
380 .raw_unregister = ir_lirc_unregister,
381};
382
383static int __init ir_lirc_codec_init(void)
384{
385 ir_raw_handler_register(&lirc_handler);
386
387 printk(KERN_INFO "IR LIRC bridge handler initialized\n");
388 return 0;
389}
390
391static void __exit ir_lirc_codec_exit(void)
392{
393 ir_raw_handler_unregister(&lirc_handler);
394}
395
396module_init(ir_lirc_codec_init);
397module_exit(ir_lirc_codec_exit);
398
399MODULE_LICENSE("GPL");
400MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
401MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
402MODULE_DESCRIPTION("LIRC IR handler bridge");
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
new file mode 100644
index 000000000000..7b58b4a1729b
--- /dev/null
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -0,0 +1,220 @@
1/* ir-nec-decoder.c - handle NEC IR Pulse/Space protocol
2 *
3 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/bitrev.h>
16#include "rc-core-priv.h"
17
18#define NEC_NBITS 32
19#define NEC_UNIT 562500 /* ns */
20#define NEC_HEADER_PULSE (16 * NEC_UNIT)
21#define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */
22#define NEC_HEADER_SPACE (8 * NEC_UNIT)
23#define NEC_REPEAT_SPACE (4 * NEC_UNIT)
24#define NEC_BIT_PULSE (1 * NEC_UNIT)
25#define NEC_BIT_0_SPACE (1 * NEC_UNIT)
26#define NEC_BIT_1_SPACE (3 * NEC_UNIT)
27#define NEC_TRAILER_PULSE (1 * NEC_UNIT)
28#define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */
29#define NECX_REPEAT_BITS 1
30
31enum nec_state {
32 STATE_INACTIVE,
33 STATE_HEADER_SPACE,
34 STATE_BIT_PULSE,
35 STATE_BIT_SPACE,
36 STATE_TRAILER_PULSE,
37 STATE_TRAILER_SPACE,
38};
39
40/**
41 * ir_nec_decode() - Decode one NEC pulse or space
42 * @dev: the struct rc_dev descriptor of the device
43 * @duration: the struct ir_raw_event descriptor of the pulse/space
44 *
45 * This function returns -EINVAL if the pulse violates the state machine
46 */
47static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
48{
49 struct nec_dec *data = &dev->raw->nec;
50 u32 scancode;
51 u8 address, not_address, command, not_command;
52
53 if (!(dev->raw->enabled_protocols & RC_TYPE_NEC))
54 return 0;
55
56 if (!is_timing_event(ev)) {
57 if (ev.reset)
58 data->state = STATE_INACTIVE;
59 return 0;
60 }
61
62 IR_dprintk(2, "NEC decode started at state %d (%uus %s)\n",
63 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
64
65 switch (data->state) {
66
67 case STATE_INACTIVE:
68 if (!ev.pulse)
69 break;
70
71 if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
72 data->is_nec_x = false;
73 data->necx_repeat = false;
74 } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
75 data->is_nec_x = true;
76 else
77 break;
78
79 data->count = 0;
80 data->state = STATE_HEADER_SPACE;
81 return 0;
82
83 case STATE_HEADER_SPACE:
84 if (ev.pulse)
85 break;
86
87 if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
88 data->state = STATE_BIT_PULSE;
89 return 0;
90 } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
91 if (!dev->keypressed) {
92 IR_dprintk(1, "Discarding last key repeat: event after key up\n");
93 } else {
94 rc_repeat(dev);
95 IR_dprintk(1, "Repeat last key\n");
96 data->state = STATE_TRAILER_PULSE;
97 }
98 return 0;
99 }
100
101 break;
102
103 case STATE_BIT_PULSE:
104 if (!ev.pulse)
105 break;
106
107 if (!eq_margin(ev.duration, NEC_BIT_PULSE, NEC_UNIT / 2))
108 break;
109
110 data->state = STATE_BIT_SPACE;
111 return 0;
112
113 case STATE_BIT_SPACE:
114 if (ev.pulse)
115 break;
116
117 if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
118 geq_margin(ev.duration,
119 NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
120 IR_dprintk(1, "Repeat last key\n");
121 rc_repeat(dev);
122 data->state = STATE_INACTIVE;
123 return 0;
124
125 } else if (data->count > NECX_REPEAT_BITS)
126 data->necx_repeat = false;
127
128 data->bits <<= 1;
129 if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
130 data->bits |= 1;
131 else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
132 break;
133 data->count++;
134
135 if (data->count == NEC_NBITS)
136 data->state = STATE_TRAILER_PULSE;
137 else
138 data->state = STATE_BIT_PULSE;
139
140 return 0;
141
142 case STATE_TRAILER_PULSE:
143 if (!ev.pulse)
144 break;
145
146 if (!eq_margin(ev.duration, NEC_TRAILER_PULSE, NEC_UNIT / 2))
147 break;
148
149 data->state = STATE_TRAILER_SPACE;
150 return 0;
151
152 case STATE_TRAILER_SPACE:
153 if (ev.pulse)
154 break;
155
156 if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
157 break;
158
159 address = bitrev8((data->bits >> 24) & 0xff);
160 not_address = bitrev8((data->bits >> 16) & 0xff);
161 command = bitrev8((data->bits >> 8) & 0xff);
162 not_command = bitrev8((data->bits >> 0) & 0xff);
163
164 if ((command ^ not_command) != 0xff) {
165 IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
166 data->bits);
167 break;
168 }
169
170 if ((address ^ not_address) != 0xff) {
171 /* Extended NEC */
172 scancode = address << 16 |
173 not_address << 8 |
174 command;
175 IR_dprintk(1, "NEC (Ext) scancode 0x%06x\n", scancode);
176 } else {
177 /* Normal NEC */
178 scancode = address << 8 | command;
179 IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
180 }
181
182 if (data->is_nec_x)
183 data->necx_repeat = true;
184
185 rc_keydown(dev, scancode, 0);
186 data->state = STATE_INACTIVE;
187 return 0;
188 }
189
190 IR_dprintk(1, "NEC decode failed at state %d (%uus %s)\n",
191 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
192 data->state = STATE_INACTIVE;
193 return -EINVAL;
194}
195
196static struct ir_raw_handler nec_handler = {
197 .protocols = RC_TYPE_NEC,
198 .decode = ir_nec_decode,
199};
200
201static int __init ir_nec_decode_init(void)
202{
203 ir_raw_handler_register(&nec_handler);
204
205 printk(KERN_INFO "IR NEC protocol handler initialized\n");
206 return 0;
207}
208
209static void __exit ir_nec_decode_exit(void)
210{
211 ir_raw_handler_unregister(&nec_handler);
212}
213
214module_init(ir_nec_decode_init);
215module_exit(ir_nec_decode_exit);
216
217MODULE_LICENSE("GPL");
218MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
219MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
220MODULE_DESCRIPTION("NEC IR protocol decoder");
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
new file mode 100644
index 000000000000..185baddcbf14
--- /dev/null
+++ b/drivers/media/rc/ir-raw.c
@@ -0,0 +1,371 @@
1/* ir-raw.c - handle IR pulse/space events
2 *
3 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/kthread.h>
16#include <linux/mutex.h>
17#include <linux/sched.h>
18#include <linux/freezer.h>
19#include "rc-core-priv.h"
20
21/* Define the max number of pulse/space transitions to buffer */
22#define MAX_IR_EVENT_SIZE 512
23
24/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
25static LIST_HEAD(ir_raw_client_list);
26
27/* Used to handle IR raw handler extensions */
28static DEFINE_MUTEX(ir_raw_handler_lock);
29static LIST_HEAD(ir_raw_handler_list);
30static u64 available_protocols;
31
32#ifdef MODULE
33/* Used to load the decoders */
34static struct work_struct wq_load;
35#endif
36
37static int ir_raw_event_thread(void *data)
38{
39 struct ir_raw_event ev;
40 struct ir_raw_handler *handler;
41 struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
42 int retval;
43
44 while (!kthread_should_stop()) {
45
46 spin_lock_irq(&raw->lock);
47 retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
48
49 if (!retval) {
50 set_current_state(TASK_INTERRUPTIBLE);
51
52 if (kthread_should_stop())
53 set_current_state(TASK_RUNNING);
54
55 spin_unlock_irq(&raw->lock);
56 schedule();
57 continue;
58 }
59
60 spin_unlock_irq(&raw->lock);
61
62
63 BUG_ON(retval != sizeof(ev));
64
65 mutex_lock(&ir_raw_handler_lock);
66 list_for_each_entry(handler, &ir_raw_handler_list, list)
67 handler->decode(raw->dev, ev);
68 raw->prev_ev = ev;
69 mutex_unlock(&ir_raw_handler_lock);
70 }
71
72 return 0;
73}
74
75/**
76 * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
77 * @dev: the struct rc_dev device descriptor
78 * @ev: the struct ir_raw_event descriptor of the pulse/space
79 *
80 * This routine (which may be called from an interrupt context) stores a
81 * pulse/space duration for the raw ir decoding state machines. Pulses are
82 * signalled as positive values and spaces as negative values. A zero value
83 * will reset the decoding state machines.
84 */
85int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
86{
87 if (!dev->raw)
88 return -EINVAL;
89
90 IR_dprintk(2, "sample: (%05dus %s)\n",
91 TO_US(ev->duration), TO_STR(ev->pulse));
92
93 if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
94 return -ENOMEM;
95
96 return 0;
97}
98EXPORT_SYMBOL_GPL(ir_raw_event_store);
99
100/**
101 * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
102 * @dev: the struct rc_dev device descriptor
103 * @type: the type of the event that has occurred
104 *
105 * This routine (which may be called from an interrupt context) is used to
106 * store the beginning of an ir pulse or space (or the start/end of ir
107 * reception) for the raw ir decoding state machines. This is used by
108 * hardware which does not provide durations directly but only interrupts
109 * (or similar events) on state change.
110 */
111int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
112{
113 ktime_t now;
114 s64 delta; /* ns */
115 struct ir_raw_event ev;
116 int rc = 0;
117
118 if (!dev->raw)
119 return -EINVAL;
120
121 now = ktime_get();
122 delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
123
124 /* Check for a long duration since last event or if we're
125 * being called for the first time, note that delta can't
126 * possibly be negative.
127 */
128 ev.duration = 0;
129 if (delta > IR_MAX_DURATION || !dev->raw->last_type)
130 type |= IR_START_EVENT;
131 else
132 ev.duration = delta;
133
134 if (type & IR_START_EVENT)
135 ir_raw_event_reset(dev);
136 else if (dev->raw->last_type & IR_SPACE) {
137 ev.pulse = false;
138 rc = ir_raw_event_store(dev, &ev);
139 } else if (dev->raw->last_type & IR_PULSE) {
140 ev.pulse = true;
141 rc = ir_raw_event_store(dev, &ev);
142 } else
143 return 0;
144
145 dev->raw->last_event = now;
146 dev->raw->last_type = type;
147 return rc;
148}
149EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
150
151/**
152 * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
153 * @dev: the struct rc_dev device descriptor
154 * @type: the type of the event that has occurred
155 *
156 * This routine (which may be called from an interrupt context) works
157 * in similiar manner to ir_raw_event_store_edge.
158 * This routine is intended for devices with limited internal buffer
159 * It automerges samples of same type, and handles timeouts
160 */
161int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
162{
163 if (!dev->raw)
164 return -EINVAL;
165
166 /* Ignore spaces in idle mode */
167 if (dev->idle && !ev->pulse)
168 return 0;
169 else if (dev->idle)
170 ir_raw_event_set_idle(dev, false);
171
172 if (!dev->raw->this_ev.duration)
173 dev->raw->this_ev = *ev;
174 else if (ev->pulse == dev->raw->this_ev.pulse)
175 dev->raw->this_ev.duration += ev->duration;
176 else {
177 ir_raw_event_store(dev, &dev->raw->this_ev);
178 dev->raw->this_ev = *ev;
179 }
180
181 /* Enter idle mode if nessesary */
182 if (!ev->pulse && dev->timeout &&
183 dev->raw->this_ev.duration >= dev->timeout)
184 ir_raw_event_set_idle(dev, true);
185
186 return 0;
187}
188EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
189
190/**
191 * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not
192 * @dev: the struct rc_dev device descriptor
193 * @idle: whether the device is idle or not
194 */
195void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
196{
197 if (!dev->raw)
198 return;
199
200 IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
201
202 if (idle) {
203 dev->raw->this_ev.timeout = true;
204 ir_raw_event_store(dev, &dev->raw->this_ev);
205 init_ir_raw_event(&dev->raw->this_ev);
206 }
207
208 if (dev->s_idle)
209 dev->s_idle(dev, idle);
210
211 dev->idle = idle;
212}
213EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
214
215/**
216 * ir_raw_event_handle() - schedules the decoding of stored ir data
217 * @dev: the struct rc_dev device descriptor
218 *
219 * This routine will tell rc-core to start decoding stored ir data.
220 */
221void ir_raw_event_handle(struct rc_dev *dev)
222{
223 unsigned long flags;
224
225 if (!dev->raw)
226 return;
227
228 spin_lock_irqsave(&dev->raw->lock, flags);
229 wake_up_process(dev->raw->thread);
230 spin_unlock_irqrestore(&dev->raw->lock, flags);
231}
232EXPORT_SYMBOL_GPL(ir_raw_event_handle);
233
234/* used internally by the sysfs interface */
235u64
236ir_raw_get_allowed_protocols()
237{
238 u64 protocols;
239 mutex_lock(&ir_raw_handler_lock);
240 protocols = available_protocols;
241 mutex_unlock(&ir_raw_handler_lock);
242 return protocols;
243}
244
245/*
246 * Used to (un)register raw event clients
247 */
248int ir_raw_event_register(struct rc_dev *dev)
249{
250 int rc;
251 struct ir_raw_handler *handler;
252
253 if (!dev)
254 return -EINVAL;
255
256 dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
257 if (!dev->raw)
258 return -ENOMEM;
259
260 dev->raw->dev = dev;
261 dev->raw->enabled_protocols = ~0;
262 rc = kfifo_alloc(&dev->raw->kfifo,
263 sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
264 GFP_KERNEL);
265 if (rc < 0)
266 goto out;
267
268 spin_lock_init(&dev->raw->lock);
269 dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
270 "rc%ld", dev->devno);
271
272 if (IS_ERR(dev->raw->thread)) {
273 rc = PTR_ERR(dev->raw->thread);
274 goto out;
275 }
276
277 mutex_lock(&ir_raw_handler_lock);
278 list_add_tail(&dev->raw->list, &ir_raw_client_list);
279 list_for_each_entry(handler, &ir_raw_handler_list, list)
280 if (handler->raw_register)
281 handler->raw_register(dev);
282 mutex_unlock(&ir_raw_handler_lock);
283
284 return 0;
285
286out:
287 kfree(dev->raw);
288 dev->raw = NULL;
289 return rc;
290}
291
292void ir_raw_event_unregister(struct rc_dev *dev)
293{
294 struct ir_raw_handler *handler;
295
296 if (!dev || !dev->raw)
297 return;
298
299 kthread_stop(dev->raw->thread);
300
301 mutex_lock(&ir_raw_handler_lock);
302 list_del(&dev->raw->list);
303 list_for_each_entry(handler, &ir_raw_handler_list, list)
304 if (handler->raw_unregister)
305 handler->raw_unregister(dev);
306 mutex_unlock(&ir_raw_handler_lock);
307
308 kfifo_free(&dev->raw->kfifo);
309 kfree(dev->raw);
310 dev->raw = NULL;
311}
312
313/*
314 * Extension interface - used to register the IR decoders
315 */
316
317int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
318{
319 struct ir_raw_event_ctrl *raw;
320
321 mutex_lock(&ir_raw_handler_lock);
322 list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
323 if (ir_raw_handler->raw_register)
324 list_for_each_entry(raw, &ir_raw_client_list, list)
325 ir_raw_handler->raw_register(raw->dev);
326 available_protocols |= ir_raw_handler->protocols;
327 mutex_unlock(&ir_raw_handler_lock);
328
329 return 0;
330}
331EXPORT_SYMBOL(ir_raw_handler_register);
332
333void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
334{
335 struct ir_raw_event_ctrl *raw;
336
337 mutex_lock(&ir_raw_handler_lock);
338 list_del(&ir_raw_handler->list);
339 if (ir_raw_handler->raw_unregister)
340 list_for_each_entry(raw, &ir_raw_client_list, list)
341 ir_raw_handler->raw_unregister(raw->dev);
342 available_protocols &= ~ir_raw_handler->protocols;
343 mutex_unlock(&ir_raw_handler_lock);
344}
345EXPORT_SYMBOL(ir_raw_handler_unregister);
346
347#ifdef MODULE
348static void init_decoders(struct work_struct *work)
349{
350 /* Load the decoder modules */
351
352 load_nec_decode();
353 load_rc5_decode();
354 load_rc6_decode();
355 load_jvc_decode();
356 load_sony_decode();
357 load_lirc_codec();
358
359 /* If needed, we may later add some init code. In this case,
360 it is needed to change the CONFIG_MODULE test at rc-core.h
361 */
362}
363#endif
364
365void ir_raw_init(void)
366{
367#ifdef MODULE
368 INIT_WORK(&wq_load, init_decoders);
369 schedule_work(&wq_load);
370#endif
371}
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
new file mode 100644
index 000000000000..ebdba5539916
--- /dev/null
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -0,0 +1,189 @@
1/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol
2 *
3 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15/*
16 * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols.
17 * There are other variants that use a different number of bits.
18 * This is currently unsupported.
19 * It considers a carrier of 36 kHz, with a total of 14/20 bits, where
20 * the first two bits are start bits, and a third one is a filing bit
21 */
22
23#include "rc-core-priv.h"
24
25#define RC5_NBITS 14
26#define RC5X_NBITS 20
27#define CHECK_RC5X_NBITS 8
28#define RC5_UNIT 888888 /* ns */
29#define RC5_BIT_START (1 * RC5_UNIT)
30#define RC5_BIT_END (1 * RC5_UNIT)
31#define RC5X_SPACE (4 * RC5_UNIT)
32
33enum rc5_state {
34 STATE_INACTIVE,
35 STATE_BIT_START,
36 STATE_BIT_END,
37 STATE_CHECK_RC5X,
38 STATE_FINISHED,
39};
40
41/**
42 * ir_rc5_decode() - Decode one RC-5 pulse or space
43 * @dev: the struct rc_dev descriptor of the device
44 * @ev: the struct ir_raw_event descriptor of the pulse/space
45 *
46 * This function returns -EINVAL if the pulse violates the state machine
47 */
48static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
49{
50 struct rc5_dec *data = &dev->raw->rc5;
51 u8 toggle;
52 u32 scancode;
53
54 if (!(dev->raw->enabled_protocols & RC_TYPE_RC5))
55 return 0;
56
57 if (!is_timing_event(ev)) {
58 if (ev.reset)
59 data->state = STATE_INACTIVE;
60 return 0;
61 }
62
63 if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
64 goto out;
65
66again:
67 IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
68 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
69
70 if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
71 return 0;
72
73 switch (data->state) {
74
75 case STATE_INACTIVE:
76 if (!ev.pulse)
77 break;
78
79 data->state = STATE_BIT_START;
80 data->count = 1;
81 /* We just need enough bits to get to STATE_CHECK_RC5X */
82 data->wanted_bits = RC5X_NBITS;
83 decrease_duration(&ev, RC5_BIT_START);
84 goto again;
85
86 case STATE_BIT_START:
87 if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
88 break;
89
90 data->bits <<= 1;
91 if (!ev.pulse)
92 data->bits |= 1;
93 data->count++;
94 data->state = STATE_BIT_END;
95 return 0;
96
97 case STATE_BIT_END:
98 if (!is_transition(&ev, &dev->raw->prev_ev))
99 break;
100
101 if (data->count == data->wanted_bits)
102 data->state = STATE_FINISHED;
103 else if (data->count == CHECK_RC5X_NBITS)
104 data->state = STATE_CHECK_RC5X;
105 else
106 data->state = STATE_BIT_START;
107
108 decrease_duration(&ev, RC5_BIT_END);
109 goto again;
110
111 case STATE_CHECK_RC5X:
112 if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
113 /* RC5X */
114 data->wanted_bits = RC5X_NBITS;
115 decrease_duration(&ev, RC5X_SPACE);
116 } else {
117 /* RC5 */
118 data->wanted_bits = RC5_NBITS;
119 }
120 data->state = STATE_BIT_START;
121 goto again;
122
123 case STATE_FINISHED:
124 if (ev.pulse)
125 break;
126
127 if (data->wanted_bits == RC5X_NBITS) {
128 /* RC5X */
129 u8 xdata, command, system;
130 xdata = (data->bits & 0x0003F) >> 0;
131 command = (data->bits & 0x00FC0) >> 6;
132 system = (data->bits & 0x1F000) >> 12;
133 toggle = (data->bits & 0x20000) ? 1 : 0;
134 command += (data->bits & 0x01000) ? 0 : 0x40;
135 scancode = system << 16 | command << 8 | xdata;
136
137 IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
138 scancode, toggle);
139
140 } else {
141 /* RC5 */
142 u8 command, system;
143 command = (data->bits & 0x0003F) >> 0;
144 system = (data->bits & 0x007C0) >> 6;
145 toggle = (data->bits & 0x00800) ? 1 : 0;
146 command += (data->bits & 0x01000) ? 0 : 0x40;
147 scancode = system << 8 | command;
148
149 IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
150 scancode, toggle);
151 }
152
153 rc_keydown(dev, scancode, toggle);
154 data->state = STATE_INACTIVE;
155 return 0;
156 }
157
158out:
159 IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
160 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
161 data->state = STATE_INACTIVE;
162 return -EINVAL;
163}
164
165static struct ir_raw_handler rc5_handler = {
166 .protocols = RC_TYPE_RC5,
167 .decode = ir_rc5_decode,
168};
169
170static int __init ir_rc5_decode_init(void)
171{
172 ir_raw_handler_register(&rc5_handler);
173
174 printk(KERN_INFO "IR RC5(x) protocol handler initialized\n");
175 return 0;
176}
177
178static void __exit ir_rc5_decode_exit(void)
179{
180 ir_raw_handler_unregister(&rc5_handler);
181}
182
183module_init(ir_rc5_decode_init);
184module_exit(ir_rc5_decode_exit);
185
186MODULE_LICENSE("GPL");
187MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
188MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
189MODULE_DESCRIPTION("RC5(x) IR protocol decoder");
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
new file mode 100644
index 000000000000..90aa8868629a
--- /dev/null
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -0,0 +1,153 @@
1/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
2 *
3 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16/*
17 * This code handles the 15 bit RC5-ish protocol used by the Streamzap
18 * PC Remote.
19 * It considers a carrier of 36 kHz, with a total of 15 bits, where
20 * the first two bits are start bits, and a third one is a filing bit
21 */
22
23#include "rc-core-priv.h"
24
25#define RC5_SZ_NBITS 15
26#define RC5_UNIT 888888 /* ns */
27#define RC5_BIT_START (1 * RC5_UNIT)
28#define RC5_BIT_END (1 * RC5_UNIT)
29
30enum rc5_sz_state {
31 STATE_INACTIVE,
32 STATE_BIT_START,
33 STATE_BIT_END,
34 STATE_FINISHED,
35};
36
37/**
38 * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
39 * @dev: the struct rc_dev descriptor of the device
40 * @ev: the struct ir_raw_event descriptor of the pulse/space
41 *
42 * This function returns -EINVAL if the pulse violates the state machine
43 */
44static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
45{
46 struct rc5_sz_dec *data = &dev->raw->rc5_sz;
47 u8 toggle, command, system;
48 u32 scancode;
49
50 if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ))
51 return 0;
52
53 if (!is_timing_event(ev)) {
54 if (ev.reset)
55 data->state = STATE_INACTIVE;
56 return 0;
57 }
58
59 if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
60 goto out;
61
62again:
63 IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
64 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
65
66 if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
67 return 0;
68
69 switch (data->state) {
70
71 case STATE_INACTIVE:
72 if (!ev.pulse)
73 break;
74
75 data->state = STATE_BIT_START;
76 data->count = 1;
77 data->wanted_bits = RC5_SZ_NBITS;
78 decrease_duration(&ev, RC5_BIT_START);
79 goto again;
80
81 case STATE_BIT_START:
82 if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
83 break;
84
85 data->bits <<= 1;
86 if (!ev.pulse)
87 data->bits |= 1;
88 data->count++;
89 data->state = STATE_BIT_END;
90 return 0;
91
92 case STATE_BIT_END:
93 if (!is_transition(&ev, &dev->raw->prev_ev))
94 break;
95
96 if (data->count == data->wanted_bits)
97 data->state = STATE_FINISHED;
98 else
99 data->state = STATE_BIT_START;
100
101 decrease_duration(&ev, RC5_BIT_END);
102 goto again;
103
104 case STATE_FINISHED:
105 if (ev.pulse)
106 break;
107
108 /* RC5-sz */
109 command = (data->bits & 0x0003F) >> 0;
110 system = (data->bits & 0x02FC0) >> 6;
111 toggle = (data->bits & 0x01000) ? 1 : 0;
112 scancode = system << 6 | command;
113
114 IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
115 scancode, toggle);
116
117 rc_keydown(dev, scancode, toggle);
118 data->state = STATE_INACTIVE;
119 return 0;
120 }
121
122out:
123 IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
124 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
125 data->state = STATE_INACTIVE;
126 return -EINVAL;
127}
128
129static struct ir_raw_handler rc5_sz_handler = {
130 .protocols = RC_TYPE_RC5_SZ,
131 .decode = ir_rc5_sz_decode,
132};
133
134static int __init ir_rc5_sz_decode_init(void)
135{
136 ir_raw_handler_register(&rc5_sz_handler);
137
138 printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
139 return 0;
140}
141
142static void __exit ir_rc5_sz_decode_exit(void)
143{
144 ir_raw_handler_unregister(&rc5_sz_handler);
145}
146
147module_init(ir_rc5_sz_decode_init);
148module_exit(ir_rc5_sz_decode_exit);
149
150MODULE_LICENSE("GPL");
151MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
152MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
153MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
new file mode 100644
index 000000000000..755dafa3871b
--- /dev/null
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -0,0 +1,280 @@
1/* ir-rc6-decoder.c - A decoder for the RC6 IR protocol
2 *
3 * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include "rc-core-priv.h"
16
17/*
18 * This decoder currently supports:
19 * RC6-0-16 (standard toggle bit in header)
20 * RC6-6A-24 (no toggle bit)
21 * RC6-6A-32 (MCE version with toggle bit in body)
22 */
23
24#define RC6_UNIT 444444 /* us */
25#define RC6_HEADER_NBITS 4 /* not including toggle bit */
26#define RC6_0_NBITS 16
27#define RC6_6A_SMALL_NBITS 24
28#define RC6_6A_LARGE_NBITS 32
29#define RC6_PREFIX_PULSE (6 * RC6_UNIT)
30#define RC6_PREFIX_SPACE (2 * RC6_UNIT)
31#define RC6_BIT_START (1 * RC6_UNIT)
32#define RC6_BIT_END (1 * RC6_UNIT)
33#define RC6_TOGGLE_START (2 * RC6_UNIT)
34#define RC6_TOGGLE_END (2 * RC6_UNIT)
35#define RC6_MODE_MASK 0x07 /* for the header bits */
36#define RC6_STARTBIT_MASK 0x08 /* for the header bits */
37#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
38
39enum rc6_mode {
40 RC6_MODE_0,
41 RC6_MODE_6A,
42 RC6_MODE_UNKNOWN,
43};
44
45enum rc6_state {
46 STATE_INACTIVE,
47 STATE_PREFIX_SPACE,
48 STATE_HEADER_BIT_START,
49 STATE_HEADER_BIT_END,
50 STATE_TOGGLE_START,
51 STATE_TOGGLE_END,
52 STATE_BODY_BIT_START,
53 STATE_BODY_BIT_END,
54 STATE_FINISHED,
55};
56
57static enum rc6_mode rc6_mode(struct rc6_dec *data)
58{
59 switch (data->header & RC6_MODE_MASK) {
60 case 0:
61 return RC6_MODE_0;
62 case 6:
63 if (!data->toggle)
64 return RC6_MODE_6A;
65 /* fall through */
66 default:
67 return RC6_MODE_UNKNOWN;
68 }
69}
70
71/**
72 * ir_rc6_decode() - Decode one RC6 pulse or space
73 * @dev: the struct rc_dev descriptor of the device
74 * @ev: the struct ir_raw_event descriptor of the pulse/space
75 *
76 * This function returns -EINVAL if the pulse violates the state machine
77 */
78static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
79{
80 struct rc6_dec *data = &dev->raw->rc6;
81 u32 scancode;
82 u8 toggle;
83
84 if (!(dev->raw->enabled_protocols & RC_TYPE_RC6))
85 return 0;
86
87 if (!is_timing_event(ev)) {
88 if (ev.reset)
89 data->state = STATE_INACTIVE;
90 return 0;
91 }
92
93 if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
94 goto out;
95
96again:
97 IR_dprintk(2, "RC6 decode started at state %i (%uus %s)\n",
98 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
99
100 if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
101 return 0;
102
103 switch (data->state) {
104
105 case STATE_INACTIVE:
106 if (!ev.pulse)
107 break;
108
109 /* Note: larger margin on first pulse since each RC6_UNIT
110 is quite short and some hardware takes some time to
111 adjust to the signal */
112 if (!eq_margin(ev.duration, RC6_PREFIX_PULSE, RC6_UNIT))
113 break;
114
115 data->state = STATE_PREFIX_SPACE;
116 data->count = 0;
117 return 0;
118
119 case STATE_PREFIX_SPACE:
120 if (ev.pulse)
121 break;
122
123 if (!eq_margin(ev.duration, RC6_PREFIX_SPACE, RC6_UNIT / 2))
124 break;
125
126 data->state = STATE_HEADER_BIT_START;
127 return 0;
128
129 case STATE_HEADER_BIT_START:
130 if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
131 break;
132
133 data->header <<= 1;
134 if (ev.pulse)
135 data->header |= 1;
136 data->count++;
137 data->state = STATE_HEADER_BIT_END;
138 return 0;
139
140 case STATE_HEADER_BIT_END:
141 if (!is_transition(&ev, &dev->raw->prev_ev))
142 break;
143
144 if (data->count == RC6_HEADER_NBITS)
145 data->state = STATE_TOGGLE_START;
146 else
147 data->state = STATE_HEADER_BIT_START;
148
149 decrease_duration(&ev, RC6_BIT_END);
150 goto again;
151
152 case STATE_TOGGLE_START:
153 if (!eq_margin(ev.duration, RC6_TOGGLE_START, RC6_UNIT / 2))
154 break;
155
156 data->toggle = ev.pulse;
157 data->state = STATE_TOGGLE_END;
158 return 0;
159
160 case STATE_TOGGLE_END:
161 if (!is_transition(&ev, &dev->raw->prev_ev) ||
162 !geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
163 break;
164
165 if (!(data->header & RC6_STARTBIT_MASK)) {
166 IR_dprintk(1, "RC6 invalid start bit\n");
167 break;
168 }
169
170 data->state = STATE_BODY_BIT_START;
171 decrease_duration(&ev, RC6_TOGGLE_END);
172 data->count = 0;
173
174 switch (rc6_mode(data)) {
175 case RC6_MODE_0:
176 data->wanted_bits = RC6_0_NBITS;
177 break;
178 case RC6_MODE_6A:
179 /* This might look weird, but we basically
180 check the value of the first body bit to
181 determine the number of bits in mode 6A */
182 if ((!ev.pulse && !geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2)) ||
183 geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
184 data->wanted_bits = RC6_6A_LARGE_NBITS;
185 else
186 data->wanted_bits = RC6_6A_SMALL_NBITS;
187 break;
188 default:
189 IR_dprintk(1, "RC6 unknown mode\n");
190 goto out;
191 }
192 goto again;
193
194 case STATE_BODY_BIT_START:
195 if (!eq_margin(ev.duration, RC6_BIT_START, RC6_UNIT / 2))
196 break;
197
198 data->body <<= 1;
199 if (ev.pulse)
200 data->body |= 1;
201 data->count++;
202 data->state = STATE_BODY_BIT_END;
203 return 0;
204
205 case STATE_BODY_BIT_END:
206 if (!is_transition(&ev, &dev->raw->prev_ev))
207 break;
208
209 if (data->count == data->wanted_bits)
210 data->state = STATE_FINISHED;
211 else
212 data->state = STATE_BODY_BIT_START;
213
214 decrease_duration(&ev, RC6_BIT_END);
215 goto again;
216
217 case STATE_FINISHED:
218 if (ev.pulse)
219 break;
220
221 switch (rc6_mode(data)) {
222 case RC6_MODE_0:
223 scancode = data->body & 0xffff;
224 toggle = data->toggle;
225 IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
226 scancode, toggle);
227 break;
228 case RC6_MODE_6A:
229 if (data->wanted_bits == RC6_6A_LARGE_NBITS) {
230 toggle = data->body & RC6_6A_MCE_TOGGLE_MASK ? 1 : 0;
231 scancode = data->body & ~RC6_6A_MCE_TOGGLE_MASK;
232 } else {
233 toggle = 0;
234 scancode = data->body & 0xffffff;
235 }
236
237 IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
238 scancode, toggle);
239 break;
240 default:
241 IR_dprintk(1, "RC6 unknown mode\n");
242 goto out;
243 }
244
245 rc_keydown(dev, scancode, toggle);
246 data->state = STATE_INACTIVE;
247 return 0;
248 }
249
250out:
251 IR_dprintk(1, "RC6 decode failed at state %i (%uus %s)\n",
252 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
253 data->state = STATE_INACTIVE;
254 return -EINVAL;
255}
256
257static struct ir_raw_handler rc6_handler = {
258 .protocols = RC_TYPE_RC6,
259 .decode = ir_rc6_decode,
260};
261
262static int __init ir_rc6_decode_init(void)
263{
264 ir_raw_handler_register(&rc6_handler);
265
266 printk(KERN_INFO "IR RC6 protocol handler initialized\n");
267 return 0;
268}
269
270static void __exit ir_rc6_decode_exit(void)
271{
272 ir_raw_handler_unregister(&rc6_handler);
273}
274
275module_init(ir_rc6_decode_init);
276module_exit(ir_rc6_decode_exit);
277
278MODULE_LICENSE("GPL");
279MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
280MODULE_DESCRIPTION("RC6 IR protocol decoder");
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
new file mode 100644
index 000000000000..a92de80c48db
--- /dev/null
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -0,0 +1,181 @@
1/* ir-sony-decoder.c - handle Sony IR Pulse/Space protocol
2 *
3 * Copyright (C) 2010 by David Härdeman <david@hardeman.nu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/bitrev.h>
16#include "rc-core-priv.h"
17
18#define SONY_UNIT 600000 /* ns */
19#define SONY_HEADER_PULSE (4 * SONY_UNIT)
20#define SONY_HEADER_SPACE (1 * SONY_UNIT)
21#define SONY_BIT_0_PULSE (1 * SONY_UNIT)
22#define SONY_BIT_1_PULSE (2 * SONY_UNIT)
23#define SONY_BIT_SPACE (1 * SONY_UNIT)
24#define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */
25
26enum sony_state {
27 STATE_INACTIVE,
28 STATE_HEADER_SPACE,
29 STATE_BIT_PULSE,
30 STATE_BIT_SPACE,
31 STATE_FINISHED,
32};
33
34/**
35 * ir_sony_decode() - Decode one Sony pulse or space
36 * @dev: the struct rc_dev descriptor of the device
37 * @ev: the struct ir_raw_event descriptor of the pulse/space
38 *
39 * This function returns -EINVAL if the pulse violates the state machine
40 */
41static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
42{
43 struct sony_dec *data = &dev->raw->sony;
44 u32 scancode;
45 u8 device, subdevice, function;
46
47 if (!(dev->raw->enabled_protocols & RC_TYPE_SONY))
48 return 0;
49
50 if (!is_timing_event(ev)) {
51 if (ev.reset)
52 data->state = STATE_INACTIVE;
53 return 0;
54 }
55
56 if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2))
57 goto out;
58
59 IR_dprintk(2, "Sony decode started at state %d (%uus %s)\n",
60 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
61
62 switch (data->state) {
63
64 case STATE_INACTIVE:
65 if (!ev.pulse)
66 break;
67
68 if (!eq_margin(ev.duration, SONY_HEADER_PULSE, SONY_UNIT / 2))
69 break;
70
71 data->count = 0;
72 data->state = STATE_HEADER_SPACE;
73 return 0;
74
75 case STATE_HEADER_SPACE:
76 if (ev.pulse)
77 break;
78
79 if (!eq_margin(ev.duration, SONY_HEADER_SPACE, SONY_UNIT / 2))
80 break;
81
82 data->state = STATE_BIT_PULSE;
83 return 0;
84
85 case STATE_BIT_PULSE:
86 if (!ev.pulse)
87 break;
88
89 data->bits <<= 1;
90 if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
91 data->bits |= 1;
92 else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
93 break;
94
95 data->count++;
96 data->state = STATE_BIT_SPACE;
97 return 0;
98
99 case STATE_BIT_SPACE:
100 if (ev.pulse)
101 break;
102
103 if (!geq_margin(ev.duration, SONY_BIT_SPACE, SONY_UNIT / 2))
104 break;
105
106 decrease_duration(&ev, SONY_BIT_SPACE);
107
108 if (!geq_margin(ev.duration, SONY_UNIT, SONY_UNIT / 2)) {
109 data->state = STATE_BIT_PULSE;
110 return 0;
111 }
112
113 data->state = STATE_FINISHED;
114 /* Fall through */
115
116 case STATE_FINISHED:
117 if (ev.pulse)
118 break;
119
120 if (!geq_margin(ev.duration, SONY_TRAILER_SPACE, SONY_UNIT / 2))
121 break;
122
123 switch (data->count) {
124 case 12:
125 device = bitrev8((data->bits << 3) & 0xF8);
126 subdevice = 0;
127 function = bitrev8((data->bits >> 4) & 0xFE);
128 break;
129 case 15:
130 device = bitrev8((data->bits >> 0) & 0xFF);
131 subdevice = 0;
132 function = bitrev8((data->bits >> 7) & 0xFD);
133 break;
134 case 20:
135 device = bitrev8((data->bits >> 5) & 0xF8);
136 subdevice = bitrev8((data->bits >> 0) & 0xFF);
137 function = bitrev8((data->bits >> 12) & 0xFE);
138 break;
139 default:
140 IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
141 goto out;
142 }
143
144 scancode = device << 16 | subdevice << 8 | function;
145 IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
146 rc_keydown(dev, scancode, 0);
147 data->state = STATE_INACTIVE;
148 return 0;
149 }
150
151out:
152 IR_dprintk(1, "Sony decode failed at state %d (%uus %s)\n",
153 data->state, TO_US(ev.duration), TO_STR(ev.pulse));
154 data->state = STATE_INACTIVE;
155 return -EINVAL;
156}
157
158static struct ir_raw_handler sony_handler = {
159 .protocols = RC_TYPE_SONY,
160 .decode = ir_sony_decode,
161};
162
163static int __init ir_sony_decode_init(void)
164{
165 ir_raw_handler_register(&sony_handler);
166
167 printk(KERN_INFO "IR Sony protocol handler initialized\n");
168 return 0;
169}
170
171static void __exit ir_sony_decode_exit(void)
172{
173 ir_raw_handler_unregister(&sony_handler);
174}
175
176module_init(ir_sony_decode_init);
177module_exit(ir_sony_decode_exit);
178
179MODULE_LICENSE("GPL");
180MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
181MODULE_DESCRIPTION("Sony IR protocol decoder");
diff --git a/drivers/media/rc/keymaps/Kconfig b/drivers/media/rc/keymaps/Kconfig
new file mode 100644
index 000000000000..8e615fd55852
--- /dev/null
+++ b/drivers/media/rc/keymaps/Kconfig
@@ -0,0 +1,15 @@
1config RC_MAP
2 tristate "Compile Remote Controller keymap modules"
3 depends on RC_CORE
4 default y
5
6 ---help---
7 This option enables the compilation of lots of Remote
8 Controller tables. They are short tables, but if you
9 don't use a remote controller, or prefer to load the
10 tables on userspace, you should disable it.
11
12 The ir-keytable program, available at v4l-utils package
13 provide the tool and the same RC maps for load from
14 userspace. Its available at
15 http://git.linuxtv.org/v4l-utils
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
new file mode 100644
index 000000000000..0659e9f50144
--- /dev/null
+++ b/drivers/media/rc/keymaps/Makefile
@@ -0,0 +1,88 @@
1obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
2 rc-alink-dtu-m.o \
3 rc-anysee.o \
4 rc-apac-viewcomp.o \
5 rc-asus-pc39.o \
6 rc-ati-tv-wonder-hd-600.o \
7 rc-avermedia-a16d.o \
8 rc-avermedia.o \
9 rc-avermedia-cardbus.o \
10 rc-avermedia-dvbt.o \
11 rc-avermedia-m135a.o \
12 rc-avermedia-m733a-rm-k6.o \
13 rc-avermedia-rm-ks.o \
14 rc-avertv-303.o \
15 rc-azurewave-ad-tu700.o \
16 rc-behold.o \
17 rc-behold-columbus.o \
18 rc-budget-ci-old.o \
19 rc-cinergy-1400.o \
20 rc-cinergy.o \
21 rc-dib0700-nec.o \
22 rc-dib0700-rc5.o \
23 rc-digitalnow-tinytwin.o \
24 rc-digittrade.o \
25 rc-dm1105-nec.o \
26 rc-dntv-live-dvb-t.o \
27 rc-dntv-live-dvbt-pro.o \
28 rc-em-terratec.o \
29 rc-encore-enltv2.o \
30 rc-encore-enltv.o \
31 rc-encore-enltv-fm53.o \
32 rc-evga-indtube.o \
33 rc-eztv.o \
34 rc-flydvb.o \
35 rc-flyvideo.o \
36 rc-fusionhdtv-mce.o \
37 rc-gadmei-rm008z.o \
38 rc-genius-tvgo-a11mce.o \
39 rc-gotview7135.o \
40 rc-hauppauge-new.o \
41 rc-imon-mce.o \
42 rc-imon-pad.o \
43 rc-iodata-bctv7e.o \
44 rc-kaiomy.o \
45 rc-kworld-315u.o \
46 rc-kworld-plus-tv-analog.o \
47 rc-leadtek-y04g0051.o \
48 rc-lirc.o \
49 rc-lme2510.o \
50 rc-manli.o \
51 rc-msi-digivox-ii.o \
52 rc-msi-digivox-iii.o \
53 rc-msi-tvanywhere.o \
54 rc-msi-tvanywhere-plus.o \
55 rc-nebula.o \
56 rc-nec-terratec-cinergy-xs.o \
57 rc-norwood.o \
58 rc-npgtech.o \
59 rc-pctv-sedna.o \
60 rc-pinnacle-color.o \
61 rc-pinnacle-grey.o \
62 rc-pinnacle-pctv-hd.o \
63 rc-pixelview.o \
64 rc-pixelview-mk12.o \
65 rc-pixelview-002t.o \
66 rc-pixelview-new.o \
67 rc-powercolor-real-angel.o \
68 rc-proteus-2309.o \
69 rc-purpletv.o \
70 rc-pv951.o \
71 rc-rc5-hauppauge-new.o \
72 rc-rc5-tv.o \
73 rc-rc6-mce.o \
74 rc-real-audio-220-32-keys.o \
75 rc-streamzap.o \
76 rc-tbs-nec.o \
77 rc-terratec-cinergy-xs.o \
78 rc-terratec-slim.o \
79 rc-tevii-nec.o \
80 rc-total-media-in-hand.o \
81 rc-trekstor.o \
82 rc-tt-1500.o \
83 rc-twinhan1027.o \
84 rc-videomate-m1f.o \
85 rc-videomate-s350.o \
86 rc-videomate-tv-pvr.o \
87 rc-winfast.o \
88 rc-winfast-usbii-deluxe.o
diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
new file mode 100644
index 000000000000..136d3952dedc
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
@@ -0,0 +1,89 @@
1/* adstech-dvb-t-pci.h - Keytable for adstech_dvb_t_pci Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* ADS Tech Instant TV DVB-T PCI Remote */
16
17static struct rc_map_table adstech_dvb_t_pci[] = {
18 /* Keys 0 to 9 */
19 { 0x4d, KEY_0 },
20 { 0x57, KEY_1 },
21 { 0x4f, KEY_2 },
22 { 0x53, KEY_3 },
23 { 0x56, KEY_4 },
24 { 0x4e, KEY_5 },
25 { 0x5e, KEY_6 },
26 { 0x54, KEY_7 },
27 { 0x4c, KEY_8 },
28 { 0x5c, KEY_9 },
29
30 { 0x5b, KEY_POWER },
31 { 0x5f, KEY_MUTE },
32 { 0x55, KEY_GOTO },
33 { 0x5d, KEY_SEARCH },
34 { 0x17, KEY_EPG }, /* Guide */
35 { 0x1f, KEY_MENU },
36 { 0x0f, KEY_UP },
37 { 0x46, KEY_DOWN },
38 { 0x16, KEY_LEFT },
39 { 0x1e, KEY_RIGHT },
40 { 0x0e, KEY_SELECT }, /* Enter */
41 { 0x5a, KEY_INFO },
42 { 0x52, KEY_EXIT },
43 { 0x59, KEY_PREVIOUS },
44 { 0x51, KEY_NEXT },
45 { 0x58, KEY_REWIND },
46 { 0x50, KEY_FORWARD },
47 { 0x44, KEY_PLAYPAUSE },
48 { 0x07, KEY_STOP },
49 { 0x1b, KEY_RECORD },
50 { 0x13, KEY_TUNER }, /* Live */
51 { 0x0a, KEY_A },
52 { 0x12, KEY_B },
53 { 0x03, KEY_PROG1 }, /* 1 */
54 { 0x01, KEY_PROG2 }, /* 2 */
55 { 0x00, KEY_PROG3 }, /* 3 */
56 { 0x06, KEY_DVD },
57 { 0x48, KEY_AUX }, /* Photo */
58 { 0x40, KEY_VIDEO },
59 { 0x19, KEY_AUDIO }, /* Music */
60 { 0x0b, KEY_CHANNELUP },
61 { 0x08, KEY_CHANNELDOWN },
62 { 0x15, KEY_VOLUMEUP },
63 { 0x1c, KEY_VOLUMEDOWN },
64};
65
66static struct rc_map_list adstech_dvb_t_pci_map = {
67 .map = {
68 .scan = adstech_dvb_t_pci,
69 .size = ARRAY_SIZE(adstech_dvb_t_pci),
70 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
71 .name = RC_MAP_ADSTECH_DVB_T_PCI,
72 }
73};
74
75static int __init init_rc_map_adstech_dvb_t_pci(void)
76{
77 return rc_map_register(&adstech_dvb_t_pci_map);
78}
79
80static void __exit exit_rc_map_adstech_dvb_t_pci(void)
81{
82 rc_map_unregister(&adstech_dvb_t_pci_map);
83}
84
85module_init(init_rc_map_adstech_dvb_t_pci)
86module_exit(exit_rc_map_adstech_dvb_t_pci)
87
88MODULE_LICENSE("GPL");
89MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
new file mode 100644
index 000000000000..fe652e928dc0
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
@@ -0,0 +1,68 @@
1/*
2 * A-Link DTU(m) remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */
24static struct rc_map_table alink_dtu_m[] = {
25 { 0x0800, KEY_VOLUMEUP },
26 { 0x0801, KEY_1 },
27 { 0x0802, KEY_3 },
28 { 0x0803, KEY_7 },
29 { 0x0804, KEY_9 },
30 { 0x0805, KEY_NEW }, /* symbol: PIP */
31 { 0x0806, KEY_0 },
32 { 0x0807, KEY_CHANNEL }, /* JUMP */
33 { 0x080d, KEY_5 },
34 { 0x080f, KEY_2 },
35 { 0x0812, KEY_POWER2 },
36 { 0x0814, KEY_CHANNELUP },
37 { 0x0816, KEY_VOLUMEDOWN },
38 { 0x0818, KEY_6 },
39 { 0x081a, KEY_MUTE },
40 { 0x081b, KEY_8 },
41 { 0x081c, KEY_4 },
42 { 0x081d, KEY_CHANNELDOWN },
43};
44
45static struct rc_map_list alink_dtu_m_map = {
46 .map = {
47 .scan = alink_dtu_m,
48 .size = ARRAY_SIZE(alink_dtu_m),
49 .rc_type = RC_TYPE_NEC,
50 .name = RC_MAP_ALINK_DTU_M,
51 }
52};
53
54static int __init init_rc_map_alink_dtu_m(void)
55{
56 return rc_map_register(&alink_dtu_m_map);
57}
58
59static void __exit exit_rc_map_alink_dtu_m(void)
60{
61 rc_map_unregister(&alink_dtu_m_map);
62}
63
64module_init(init_rc_map_alink_dtu_m)
65module_exit(exit_rc_map_alink_dtu_m)
66
67MODULE_LICENSE("GPL");
68MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c
new file mode 100644
index 000000000000..884f1b51a8ee
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-anysee.c
@@ -0,0 +1,93 @@
1/*
2 * Anysee remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23static struct rc_map_table anysee[] = {
24 { 0x0800, KEY_0 },
25 { 0x0801, KEY_1 },
26 { 0x0802, KEY_2 },
27 { 0x0803, KEY_3 },
28 { 0x0804, KEY_4 },
29 { 0x0805, KEY_5 },
30 { 0x0806, KEY_6 },
31 { 0x0807, KEY_7 },
32 { 0x0808, KEY_8 },
33 { 0x0809, KEY_9 },
34 { 0x080a, KEY_POWER2 }, /* [red power button] */
35 { 0x080b, KEY_VIDEO }, /* [*] MODE */
36 { 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */
37 { 0x080d, KEY_NEXT }, /* [>>|] */
38 { 0x080e, KEY_MENU }, /* MENU */
39 { 0x080f, KEY_EPG }, /* [EPG] */
40 { 0x0810, KEY_CLEAR }, /* EXIT */
41 { 0x0811, KEY_CHANNELUP },
42 { 0x0812, KEY_VOLUMEDOWN },
43 { 0x0813, KEY_VOLUMEUP },
44 { 0x0814, KEY_CHANNELDOWN },
45 { 0x0815, KEY_OK },
46 { 0x0816, KEY_RADIO }, /* [symbol TV/radio] */
47 { 0x0817, KEY_INFO }, /* [i] */
48 { 0x0818, KEY_PREVIOUS }, /* [|<<] */
49 { 0x0819, KEY_FAVORITES }, /* FAV. */
50 { 0x081a, KEY_SUBTITLE }, /* Subtitle */
51 { 0x081b, KEY_CAMERA }, /* [symbol camera] */
52 { 0x081c, KEY_YELLOW },
53 { 0x081d, KEY_RED },
54 { 0x081e, KEY_LANGUAGE }, /* [symbol Second Audio Program] */
55 { 0x081f, KEY_GREEN },
56 { 0x0820, KEY_SLEEP }, /* Sleep */
57 { 0x0821, KEY_SCREEN }, /* 16:9 / 4:3 */
58 { 0x0822, KEY_ZOOM }, /* SIZE */
59 { 0x0824, KEY_FN }, /* [F1] */
60 { 0x0825, KEY_FN }, /* [F2] */
61 { 0x0842, KEY_MUTE }, /* symbol mute */
62 { 0x0844, KEY_BLUE },
63 { 0x0847, KEY_TEXT }, /* TEXT */
64 { 0x0848, KEY_STOP },
65 { 0x0849, KEY_RECORD },
66 { 0x0850, KEY_PLAY },
67 { 0x0851, KEY_PAUSE },
68};
69
70static struct rc_map_list anysee_map = {
71 .map = {
72 .scan = anysee,
73 .size = ARRAY_SIZE(anysee),
74 .rc_type = RC_TYPE_NEC,
75 .name = RC_MAP_ANYSEE,
76 }
77};
78
79static int __init init_rc_map_anysee(void)
80{
81 return rc_map_register(&anysee_map);
82}
83
84static void __exit exit_rc_map_anysee(void)
85{
86 rc_map_unregister(&anysee_map);
87}
88
89module_init(init_rc_map_anysee)
90module_exit(exit_rc_map_anysee)
91
92MODULE_LICENSE("GPL");
93MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
new file mode 100644
index 000000000000..7af188209ff9
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
@@ -0,0 +1,80 @@
1/* apac-viewcomp.h - Keytable for apac_viewcomp Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Attila Kondoros <attila.kondoros@chello.hu> */
16
17static struct rc_map_table apac_viewcomp[] = {
18
19 { 0x01, KEY_1 },
20 { 0x02, KEY_2 },
21 { 0x03, KEY_3 },
22 { 0x04, KEY_4 },
23 { 0x05, KEY_5 },
24 { 0x06, KEY_6 },
25 { 0x07, KEY_7 },
26 { 0x08, KEY_8 },
27 { 0x09, KEY_9 },
28 { 0x00, KEY_0 },
29 { 0x17, KEY_LAST }, /* +100 */
30 { 0x0a, KEY_LIST }, /* recall */
31
32
33 { 0x1c, KEY_TUNER }, /* TV/FM */
34 { 0x15, KEY_SEARCH }, /* scan */
35 { 0x12, KEY_POWER }, /* power */
36 { 0x1f, KEY_VOLUMEDOWN }, /* vol up */
37 { 0x1b, KEY_VOLUMEUP }, /* vol down */
38 { 0x1e, KEY_CHANNELDOWN }, /* chn up */
39 { 0x1a, KEY_CHANNELUP }, /* chn down */
40
41 { 0x11, KEY_VIDEO }, /* video */
42 { 0x0f, KEY_ZOOM }, /* full screen */
43 { 0x13, KEY_MUTE }, /* mute/unmute */
44 { 0x10, KEY_TEXT }, /* min */
45
46 { 0x0d, KEY_STOP }, /* freeze */
47 { 0x0e, KEY_RECORD }, /* record */
48 { 0x1d, KEY_PLAYPAUSE }, /* stop */
49 { 0x19, KEY_PLAY }, /* play */
50
51 { 0x16, KEY_GOTO }, /* osd */
52 { 0x14, KEY_REFRESH }, /* default */
53 { 0x0c, KEY_KPPLUS }, /* fine tune >>>> */
54 { 0x18, KEY_KPMINUS }, /* fine tune <<<< */
55};
56
57static struct rc_map_list apac_viewcomp_map = {
58 .map = {
59 .scan = apac_viewcomp,
60 .size = ARRAY_SIZE(apac_viewcomp),
61 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
62 .name = RC_MAP_APAC_VIEWCOMP,
63 }
64};
65
66static int __init init_rc_map_apac_viewcomp(void)
67{
68 return rc_map_register(&apac_viewcomp_map);
69}
70
71static void __exit exit_rc_map_apac_viewcomp(void)
72{
73 rc_map_unregister(&apac_viewcomp_map);
74}
75
76module_init(init_rc_map_apac_viewcomp)
77module_exit(exit_rc_map_apac_viewcomp)
78
79MODULE_LICENSE("GPL");
80MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c
new file mode 100644
index 000000000000..b2481154491b
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-asus-pc39.c
@@ -0,0 +1,91 @@
1/* asus-pc39.h - Keytable for asus_pc39 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 * Marc Fargas <telenieko@telenieko.com>
17 * this is the remote control that comes with the asus p7131
18 * which has a label saying is "Model PC-39"
19 */
20
21static struct rc_map_table asus_pc39[] = {
22 /* Keys 0 to 9 */
23 { 0x082a, KEY_0 },
24 { 0x0816, KEY_1 },
25 { 0x0812, KEY_2 },
26 { 0x0814, KEY_3 },
27 { 0x0836, KEY_4 },
28 { 0x0832, KEY_5 },
29 { 0x0834, KEY_6 },
30 { 0x080e, KEY_7 },
31 { 0x080a, KEY_8 },
32 { 0x080c, KEY_9 },
33
34 { 0x0801, KEY_RADIO }, /* radio */
35 { 0x083c, KEY_MENU }, /* dvd/menu */
36 { 0x0815, KEY_VOLUMEUP },
37 { 0x0826, KEY_VOLUMEDOWN },
38 { 0x0808, KEY_UP },
39 { 0x0804, KEY_DOWN },
40 { 0x0818, KEY_LEFT },
41 { 0x0810, KEY_RIGHT },
42 { 0x081a, KEY_VIDEO }, /* video */
43 { 0x0806, KEY_AUDIO }, /* music */
44
45 { 0x081e, KEY_TV }, /* tv */
46 { 0x0822, KEY_EXIT }, /* back */
47 { 0x0835, KEY_CHANNELUP }, /* channel / program + */
48 { 0x0824, KEY_CHANNELDOWN }, /* channel / program - */
49 { 0x0825, KEY_ENTER }, /* enter */
50
51 { 0x0839, KEY_PAUSE }, /* play/pause */
52 { 0x0821, KEY_PREVIOUS }, /* rew */
53 { 0x0819, KEY_NEXT }, /* forward */
54 { 0x0831, KEY_REWIND }, /* backward << */
55 { 0x0805, KEY_FASTFORWARD }, /* forward >> */
56 { 0x0809, KEY_STOP },
57 { 0x0811, KEY_RECORD }, /* recording */
58 { 0x0829, KEY_POWER }, /* the button that reads "close" */
59
60 { 0x082e, KEY_ZOOM }, /* full screen */
61 { 0x082c, KEY_MACRO }, /* recall */
62 { 0x081c, KEY_HOME }, /* home */
63 { 0x083a, KEY_PVR }, /* picture */
64 { 0x0802, KEY_MUTE }, /* mute */
65 { 0x083e, KEY_DVD }, /* dvd */
66};
67
68static struct rc_map_list asus_pc39_map = {
69 .map = {
70 .scan = asus_pc39,
71 .size = ARRAY_SIZE(asus_pc39),
72 .rc_type = RC_TYPE_RC5,
73 .name = RC_MAP_ASUS_PC39,
74 }
75};
76
77static int __init init_rc_map_asus_pc39(void)
78{
79 return rc_map_register(&asus_pc39_map);
80}
81
82static void __exit exit_rc_map_asus_pc39(void)
83{
84 rc_map_unregister(&asus_pc39_map);
85}
86
87module_init(init_rc_map_asus_pc39)
88module_exit(exit_rc_map_asus_pc39)
89
90MODULE_LICENSE("GPL");
91MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
new file mode 100644
index 000000000000..f766b24b0158
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
@@ -0,0 +1,69 @@
1/* ati-tv-wonder-hd-600.h - Keytable for ati_tv_wonder_hd_600 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* ATI TV Wonder HD 600 USB
16 Devin Heitmueller <devin.heitmueller@gmail.com>
17 */
18
19static struct rc_map_table ati_tv_wonder_hd_600[] = {
20 { 0x00, KEY_RECORD}, /* Row 1 */
21 { 0x01, KEY_PLAYPAUSE},
22 { 0x02, KEY_STOP},
23 { 0x03, KEY_POWER},
24 { 0x04, KEY_PREVIOUS}, /* Row 2 */
25 { 0x05, KEY_REWIND},
26 { 0x06, KEY_FORWARD},
27 { 0x07, KEY_NEXT},
28 { 0x08, KEY_EPG}, /* Row 3 */
29 { 0x09, KEY_HOME},
30 { 0x0a, KEY_MENU},
31 { 0x0b, KEY_CHANNELUP},
32 { 0x0c, KEY_BACK}, /* Row 4 */
33 { 0x0d, KEY_UP},
34 { 0x0e, KEY_INFO},
35 { 0x0f, KEY_CHANNELDOWN},
36 { 0x10, KEY_LEFT}, /* Row 5 */
37 { 0x11, KEY_SELECT},
38 { 0x12, KEY_RIGHT},
39 { 0x13, KEY_VOLUMEUP},
40 { 0x14, KEY_LAST}, /* Row 6 */
41 { 0x15, KEY_DOWN},
42 { 0x16, KEY_MUTE},
43 { 0x17, KEY_VOLUMEDOWN},
44};
45
46static struct rc_map_list ati_tv_wonder_hd_600_map = {
47 .map = {
48 .scan = ati_tv_wonder_hd_600,
49 .size = ARRAY_SIZE(ati_tv_wonder_hd_600),
50 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
51 .name = RC_MAP_ATI_TV_WONDER_HD_600,
52 }
53};
54
55static int __init init_rc_map_ati_tv_wonder_hd_600(void)
56{
57 return rc_map_register(&ati_tv_wonder_hd_600_map);
58}
59
60static void __exit exit_rc_map_ati_tv_wonder_hd_600(void)
61{
62 rc_map_unregister(&ati_tv_wonder_hd_600_map);
63}
64
65module_init(init_rc_map_ati_tv_wonder_hd_600)
66module_exit(exit_rc_map_ati_tv_wonder_hd_600)
67
68MODULE_LICENSE("GPL");
69MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
new file mode 100644
index 000000000000..ec9beeebd410
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
@@ -0,0 +1,75 @@
1/* avermedia-a16d.h - Keytable for avermedia_a16d Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table avermedia_a16d[] = {
16 { 0x20, KEY_LIST},
17 { 0x00, KEY_POWER},
18 { 0x28, KEY_1},
19 { 0x18, KEY_2},
20 { 0x38, KEY_3},
21 { 0x24, KEY_4},
22 { 0x14, KEY_5},
23 { 0x34, KEY_6},
24 { 0x2c, KEY_7},
25 { 0x1c, KEY_8},
26 { 0x3c, KEY_9},
27 { 0x12, KEY_SUBTITLE},
28 { 0x22, KEY_0},
29 { 0x32, KEY_REWIND},
30 { 0x3a, KEY_SHUFFLE},
31 { 0x02, KEY_PRINT},
32 { 0x11, KEY_CHANNELDOWN},
33 { 0x31, KEY_CHANNELUP},
34 { 0x0c, KEY_ZOOM},
35 { 0x1e, KEY_VOLUMEDOWN},
36 { 0x3e, KEY_VOLUMEUP},
37 { 0x0a, KEY_MUTE},
38 { 0x04, KEY_AUDIO},
39 { 0x26, KEY_RECORD},
40 { 0x06, KEY_PLAY},
41 { 0x36, KEY_STOP},
42 { 0x16, KEY_PAUSE},
43 { 0x2e, KEY_REWIND},
44 { 0x0e, KEY_FASTFORWARD},
45 { 0x30, KEY_TEXT},
46 { 0x21, KEY_GREEN},
47 { 0x01, KEY_BLUE},
48 { 0x08, KEY_EPG},
49 { 0x2a, KEY_MENU},
50};
51
52static struct rc_map_list avermedia_a16d_map = {
53 .map = {
54 .scan = avermedia_a16d,
55 .size = ARRAY_SIZE(avermedia_a16d),
56 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
57 .name = RC_MAP_AVERMEDIA_A16D,
58 }
59};
60
61static int __init init_rc_map_avermedia_a16d(void)
62{
63 return rc_map_register(&avermedia_a16d_map);
64}
65
66static void __exit exit_rc_map_avermedia_a16d(void)
67{
68 rc_map_unregister(&avermedia_a16d_map);
69}
70
71module_init(init_rc_map_avermedia_a16d)
72module_exit(exit_rc_map_avermedia_a16d)
73
74MODULE_LICENSE("GPL");
75MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
new file mode 100644
index 000000000000..bdf97b74cf90
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
@@ -0,0 +1,97 @@
1/* avermedia-cardbus.h - Keytable for avermedia_cardbus Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
16
17static struct rc_map_table avermedia_cardbus[] = {
18 { 0x00, KEY_POWER },
19 { 0x01, KEY_TUNER }, /* TV/FM */
20 { 0x03, KEY_TEXT }, /* Teletext */
21 { 0x04, KEY_EPG },
22 { 0x05, KEY_1 },
23 { 0x06, KEY_2 },
24 { 0x07, KEY_3 },
25 { 0x08, KEY_AUDIO },
26 { 0x09, KEY_4 },
27 { 0x0a, KEY_5 },
28 { 0x0b, KEY_6 },
29 { 0x0c, KEY_ZOOM }, /* Full screen */
30 { 0x0d, KEY_7 },
31 { 0x0e, KEY_8 },
32 { 0x0f, KEY_9 },
33 { 0x10, KEY_PAGEUP }, /* 16-CH PREV */
34 { 0x11, KEY_0 },
35 { 0x12, KEY_INFO },
36 { 0x13, KEY_AGAIN }, /* CH RTN - channel return */
37 { 0x14, KEY_MUTE },
38 { 0x15, KEY_EDIT }, /* Autoscan */
39 { 0x17, KEY_SAVE }, /* Screenshot */
40 { 0x18, KEY_PLAYPAUSE },
41 { 0x19, KEY_RECORD },
42 { 0x1a, KEY_PLAY },
43 { 0x1b, KEY_STOP },
44 { 0x1c, KEY_FASTFORWARD },
45 { 0x1d, KEY_REWIND },
46 { 0x1e, KEY_VOLUMEDOWN },
47 { 0x1f, KEY_VOLUMEUP },
48 { 0x22, KEY_SLEEP }, /* Sleep */
49 { 0x23, KEY_ZOOM }, /* Aspect */
50 { 0x26, KEY_SCREEN }, /* Pos */
51 { 0x27, KEY_ANGLE }, /* Size */
52 { 0x28, KEY_SELECT }, /* Select */
53 { 0x29, KEY_BLUE }, /* Blue/Picture */
54 { 0x2a, KEY_BACKSPACE }, /* Back */
55 { 0x2b, KEY_MEDIA }, /* PIP (Picture-in-picture) */
56 { 0x2c, KEY_DOWN },
57 { 0x2e, KEY_DOT },
58 { 0x2f, KEY_TV }, /* Live TV */
59 { 0x32, KEY_LEFT },
60 { 0x33, KEY_CLEAR }, /* Clear */
61 { 0x35, KEY_RED }, /* Red/TV */
62 { 0x36, KEY_UP },
63 { 0x37, KEY_HOME }, /* Home */
64 { 0x39, KEY_GREEN }, /* Green/Video */
65 { 0x3d, KEY_YELLOW }, /* Yellow/Music */
66 { 0x3e, KEY_OK }, /* Ok */
67 { 0x3f, KEY_RIGHT },
68 { 0x40, KEY_NEXT }, /* Next */
69 { 0x41, KEY_PREVIOUS }, /* Previous */
70 { 0x42, KEY_CHANNELDOWN }, /* Channel down */
71 { 0x43, KEY_CHANNELUP }, /* Channel up */
72};
73
74static struct rc_map_list avermedia_cardbus_map = {
75 .map = {
76 .scan = avermedia_cardbus,
77 .size = ARRAY_SIZE(avermedia_cardbus),
78 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
79 .name = RC_MAP_AVERMEDIA_CARDBUS,
80 }
81};
82
83static int __init init_rc_map_avermedia_cardbus(void)
84{
85 return rc_map_register(&avermedia_cardbus_map);
86}
87
88static void __exit exit_rc_map_avermedia_cardbus(void)
89{
90 rc_map_unregister(&avermedia_cardbus_map);
91}
92
93module_init(init_rc_map_avermedia_cardbus)
94module_exit(exit_rc_map_avermedia_cardbus)
95
96MODULE_LICENSE("GPL");
97MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
new file mode 100644
index 000000000000..3ddb41bc075e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
@@ -0,0 +1,78 @@
1/* avermedia-dvbt.h - Keytable for avermedia_dvbt Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Matt Jesson <dvb@jesson.eclipse.co.uk */
16
17static struct rc_map_table avermedia_dvbt[] = {
18 { 0x28, KEY_0 }, /* '0' / 'enter' */
19 { 0x22, KEY_1 }, /* '1' */
20 { 0x12, KEY_2 }, /* '2' / 'up arrow' */
21 { 0x32, KEY_3 }, /* '3' */
22 { 0x24, KEY_4 }, /* '4' / 'left arrow' */
23 { 0x14, KEY_5 }, /* '5' */
24 { 0x34, KEY_6 }, /* '6' / 'right arrow' */
25 { 0x26, KEY_7 }, /* '7' */
26 { 0x16, KEY_8 }, /* '8' / 'down arrow' */
27 { 0x36, KEY_9 }, /* '9' */
28
29 { 0x20, KEY_LIST }, /* 'source' */
30 { 0x10, KEY_TEXT }, /* 'teletext' */
31 { 0x00, KEY_POWER }, /* 'power' */
32 { 0x04, KEY_AUDIO }, /* 'audio' */
33 { 0x06, KEY_ZOOM }, /* 'full screen' */
34 { 0x18, KEY_VIDEO }, /* 'display' */
35 { 0x38, KEY_SEARCH }, /* 'loop' */
36 { 0x08, KEY_INFO }, /* 'preview' */
37 { 0x2a, KEY_REWIND }, /* 'backward <<' */
38 { 0x1a, KEY_FASTFORWARD }, /* 'forward >>' */
39 { 0x3a, KEY_RECORD }, /* 'capture' */
40 { 0x0a, KEY_MUTE }, /* 'mute' */
41 { 0x2c, KEY_RECORD }, /* 'record' */
42 { 0x1c, KEY_PAUSE }, /* 'pause' */
43 { 0x3c, KEY_STOP }, /* 'stop' */
44 { 0x0c, KEY_PLAY }, /* 'play' */
45 { 0x2e, KEY_RED }, /* 'red' */
46 { 0x01, KEY_BLUE }, /* 'blue' / 'cancel' */
47 { 0x0e, KEY_YELLOW }, /* 'yellow' / 'ok' */
48 { 0x21, KEY_GREEN }, /* 'green' */
49 { 0x11, KEY_CHANNELDOWN }, /* 'channel -' */
50 { 0x31, KEY_CHANNELUP }, /* 'channel +' */
51 { 0x1e, KEY_VOLUMEDOWN }, /* 'volume -' */
52 { 0x3e, KEY_VOLUMEUP }, /* 'volume +' */
53};
54
55static struct rc_map_list avermedia_dvbt_map = {
56 .map = {
57 .scan = avermedia_dvbt,
58 .size = ARRAY_SIZE(avermedia_dvbt),
59 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
60 .name = RC_MAP_AVERMEDIA_DVBT,
61 }
62};
63
64static int __init init_rc_map_avermedia_dvbt(void)
65{
66 return rc_map_register(&avermedia_dvbt_map);
67}
68
69static void __exit exit_rc_map_avermedia_dvbt(void)
70{
71 rc_map_unregister(&avermedia_dvbt_map);
72}
73
74module_init(init_rc_map_avermedia_dvbt)
75module_exit(exit_rc_map_avermedia_dvbt)
76
77MODULE_LICENSE("GPL");
78MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
new file mode 100644
index 000000000000..357fea58a46e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
@@ -0,0 +1,147 @@
1/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers
2 *
3 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-map.h>
13
14/*
15 * Avermedia M135A with RM-JX and RM-K6 remote controls
16 *
17 * On Avermedia M135A with IR model RM-JX, the same codes exist on both
18 * Positivo (BR) and original IR, initial version and remote control codes
19 * added by Mauro Carvalho Chehab <mchehab@infradead.org>
20 *
21 * Positivo also ships Avermedia M135A with model RM-K6, extra control
22 * codes added by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
23 */
24
25static struct rc_map_table avermedia_m135a[] = {
26 /* RM-JX */
27 { 0x0200, KEY_POWER2 },
28 { 0x022e, KEY_DOT }, /* '.' */
29 { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */
30
31 { 0x0205, KEY_1 },
32 { 0x0206, KEY_2 },
33 { 0x0207, KEY_3 },
34 { 0x0209, KEY_4 },
35 { 0x020a, KEY_5 },
36 { 0x020b, KEY_6 },
37 { 0x020d, KEY_7 },
38 { 0x020e, KEY_8 },
39 { 0x020f, KEY_9 },
40 { 0x0211, KEY_0 },
41
42 { 0x0213, KEY_RIGHT }, /* -> or L */
43 { 0x0212, KEY_LEFT }, /* <- or R */
44
45 { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */
46 { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */
47
48 { 0x0303, KEY_CHANNELUP },
49 { 0x0302, KEY_CHANNELDOWN },
50 { 0x021f, KEY_VOLUMEUP },
51 { 0x021e, KEY_VOLUMEDOWN },
52 { 0x020c, KEY_ENTER }, /* Full Screen */
53
54 { 0x0214, KEY_MUTE },
55 { 0x0208, KEY_AUDIO },
56
57 { 0x0203, KEY_TEXT }, /* Teletext */
58 { 0x0204, KEY_EPG },
59 { 0x022b, KEY_TV2 }, /* TV2 or PIP */
60
61 { 0x021d, KEY_RED },
62 { 0x021c, KEY_YELLOW },
63 { 0x0301, KEY_GREEN },
64 { 0x0300, KEY_BLUE },
65
66 { 0x021a, KEY_PLAYPAUSE },
67 { 0x0219, KEY_RECORD },
68 { 0x0218, KEY_PLAY },
69 { 0x021b, KEY_STOP },
70
71 /* RM-K6 */
72 { 0x0401, KEY_POWER2 },
73 { 0x0406, KEY_MUTE },
74 { 0x0408, KEY_MODE }, /* TV/FM */
75
76 { 0x0409, KEY_1 },
77 { 0x040a, KEY_2 },
78 { 0x040b, KEY_3 },
79 { 0x040c, KEY_4 },
80 { 0x040d, KEY_5 },
81 { 0x040e, KEY_6 },
82 { 0x040f, KEY_7 },
83 { 0x0410, KEY_8 },
84 { 0x0411, KEY_9 },
85 { 0x044c, KEY_DOT }, /* '.' */
86 { 0x0412, KEY_0 },
87 { 0x0407, KEY_REFRESH }, /* Refresh/Reload */
88
89 { 0x0413, KEY_AUDIO },
90 { 0x0440, KEY_SCREEN }, /* Full Screen toggle */
91 { 0x0441, KEY_HOME },
92 { 0x0442, KEY_BACK },
93 { 0x0447, KEY_UP },
94 { 0x0448, KEY_DOWN },
95 { 0x0449, KEY_LEFT },
96 { 0x044a, KEY_RIGHT },
97 { 0x044b, KEY_OK },
98 { 0x0404, KEY_VOLUMEUP },
99 { 0x0405, KEY_VOLUMEDOWN },
100 { 0x0402, KEY_CHANNELUP },
101 { 0x0403, KEY_CHANNELDOWN },
102
103 { 0x0443, KEY_RED },
104 { 0x0444, KEY_GREEN },
105 { 0x0445, KEY_YELLOW },
106 { 0x0446, KEY_BLUE },
107
108 { 0x0414, KEY_TEXT },
109 { 0x0415, KEY_EPG },
110 { 0x041a, KEY_TV2 }, /* PIP */
111 { 0x041b, KEY_MHP }, /* Snapshot */
112
113 { 0x0417, KEY_RECORD },
114 { 0x0416, KEY_PLAYPAUSE },
115 { 0x0418, KEY_STOP },
116 { 0x0419, KEY_PAUSE },
117
118 { 0x041f, KEY_PREVIOUS },
119 { 0x041c, KEY_REWIND },
120 { 0x041d, KEY_FORWARD },
121 { 0x041e, KEY_NEXT },
122};
123
124static struct rc_map_list avermedia_m135a_map = {
125 .map = {
126 .scan = avermedia_m135a,
127 .size = ARRAY_SIZE(avermedia_m135a),
128 .rc_type = RC_TYPE_NEC,
129 .name = RC_MAP_AVERMEDIA_M135A,
130 }
131};
132
133static int __init init_rc_map_avermedia_m135a(void)
134{
135 return rc_map_register(&avermedia_m135a_map);
136}
137
138static void __exit exit_rc_map_avermedia_m135a(void)
139{
140 rc_map_unregister(&avermedia_m135a_map);
141}
142
143module_init(init_rc_map_avermedia_m135a)
144module_exit(exit_rc_map_avermedia_m135a)
145
146MODULE_LICENSE("GPL");
147MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
new file mode 100644
index 000000000000..e694e6eac37e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
@@ -0,0 +1,95 @@
1/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller
2 *
3 * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11#include <media/rc-map.h>
12
13/*
14 * Avermedia M733A with IR model RM-K6
15 * This is the stock remote controller used with Positivo machines with M733A
16 * Herton Ronaldo Krzesinski <herton@mandriva.com.br>
17 */
18
19static struct rc_map_table avermedia_m733a_rm_k6[] = {
20 { 0x0401, KEY_POWER2 },
21 { 0x0406, KEY_MUTE },
22 { 0x0408, KEY_MODE }, /* TV/FM */
23
24 { 0x0409, KEY_1 },
25 { 0x040a, KEY_2 },
26 { 0x040b, KEY_3 },
27 { 0x040c, KEY_4 },
28 { 0x040d, KEY_5 },
29 { 0x040e, KEY_6 },
30 { 0x040f, KEY_7 },
31 { 0x0410, KEY_8 },
32 { 0x0411, KEY_9 },
33 { 0x044c, KEY_DOT }, /* '.' */
34 { 0x0412, KEY_0 },
35 { 0x0407, KEY_REFRESH }, /* Refresh/Reload */
36
37 { 0x0413, KEY_AUDIO },
38 { 0x0440, KEY_SCREEN }, /* Full Screen toggle */
39 { 0x0441, KEY_HOME },
40 { 0x0442, KEY_BACK },
41 { 0x0447, KEY_UP },
42 { 0x0448, KEY_DOWN },
43 { 0x0449, KEY_LEFT },
44 { 0x044a, KEY_RIGHT },
45 { 0x044b, KEY_OK },
46 { 0x0404, KEY_VOLUMEUP },
47 { 0x0405, KEY_VOLUMEDOWN },
48 { 0x0402, KEY_CHANNELUP },
49 { 0x0403, KEY_CHANNELDOWN },
50
51 { 0x0443, KEY_RED },
52 { 0x0444, KEY_GREEN },
53 { 0x0445, KEY_YELLOW },
54 { 0x0446, KEY_BLUE },
55
56 { 0x0414, KEY_TEXT },
57 { 0x0415, KEY_EPG },
58 { 0x041a, KEY_TV2 }, /* PIP */
59 { 0x041b, KEY_MHP }, /* Snapshot */
60
61 { 0x0417, KEY_RECORD },
62 { 0x0416, KEY_PLAYPAUSE },
63 { 0x0418, KEY_STOP },
64 { 0x0419, KEY_PAUSE },
65
66 { 0x041f, KEY_PREVIOUS },
67 { 0x041c, KEY_REWIND },
68 { 0x041d, KEY_FORWARD },
69 { 0x041e, KEY_NEXT },
70};
71
72static struct rc_map_list avermedia_m733a_rm_k6_map = {
73 .map = {
74 .scan = avermedia_m733a_rm_k6,
75 .size = ARRAY_SIZE(avermedia_m733a_rm_k6),
76 .rc_type = RC_TYPE_NEC,
77 .name = RC_MAP_AVERMEDIA_M733A_RM_K6,
78 }
79};
80
81static int __init init_rc_map_avermedia_m733a_rm_k6(void)
82{
83 return rc_map_register(&avermedia_m733a_rm_k6_map);
84}
85
86static void __exit exit_rc_map_avermedia_m733a_rm_k6(void)
87{
88 rc_map_unregister(&avermedia_m733a_rm_k6_map);
89}
90
91module_init(init_rc_map_avermedia_m733a_rm_k6)
92module_exit(exit_rc_map_avermedia_m733a_rm_k6)
93
94MODULE_LICENSE("GPL");
95MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
new file mode 100644
index 000000000000..f4ca1fff455d
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
@@ -0,0 +1,79 @@
1/*
2 * AverMedia RM-KS remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23/* Initial keytable is from Jose Alberto Reguero <jareguero@telefonica.net>
24 and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */
25/* FIXME: mappings are not 100% correct? */
26static struct rc_map_table avermedia_rm_ks[] = {
27 { 0x0501, KEY_POWER2 },
28 { 0x0502, KEY_CHANNELUP },
29 { 0x0503, KEY_CHANNELDOWN },
30 { 0x0504, KEY_VOLUMEUP },
31 { 0x0505, KEY_VOLUMEDOWN },
32 { 0x0506, KEY_MUTE },
33 { 0x0507, KEY_RIGHT },
34 { 0x0508, KEY_PROG1 },
35 { 0x0509, KEY_1 },
36 { 0x050a, KEY_2 },
37 { 0x050b, KEY_3 },
38 { 0x050c, KEY_4 },
39 { 0x050d, KEY_5 },
40 { 0x050e, KEY_6 },
41 { 0x050f, KEY_7 },
42 { 0x0510, KEY_8 },
43 { 0x0511, KEY_9 },
44 { 0x0512, KEY_0 },
45 { 0x0513, KEY_AUDIO },
46 { 0x0515, KEY_EPG },
47 { 0x0516, KEY_PLAY },
48 { 0x0517, KEY_RECORD },
49 { 0x0518, KEY_STOP },
50 { 0x051c, KEY_BACK },
51 { 0x051d, KEY_FORWARD },
52 { 0x054d, KEY_LEFT },
53 { 0x0556, KEY_ZOOM },
54};
55
56static struct rc_map_list avermedia_rm_ks_map = {
57 .map = {
58 .scan = avermedia_rm_ks,
59 .size = ARRAY_SIZE(avermedia_rm_ks),
60 .rc_type = RC_TYPE_NEC,
61 .name = RC_MAP_AVERMEDIA_RM_KS,
62 }
63};
64
65static int __init init_rc_map_avermedia_rm_ks(void)
66{
67 return rc_map_register(&avermedia_rm_ks_map);
68}
69
70static void __exit exit_rc_map_avermedia_rm_ks(void)
71{
72 rc_map_unregister(&avermedia_rm_ks_map);
73}
74
75module_init(init_rc_map_avermedia_rm_ks)
76module_exit(exit_rc_map_avermedia_rm_ks)
77
78MODULE_LICENSE("GPL");
79MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c
new file mode 100644
index 000000000000..edfa71506d3e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia.c
@@ -0,0 +1,86 @@
1/* avermedia.h - Keytable for avermedia Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Alex Hermann <gaaf@gmx.net> */
16
17static struct rc_map_table avermedia[] = {
18 { 0x28, KEY_1 },
19 { 0x18, KEY_2 },
20 { 0x38, KEY_3 },
21 { 0x24, KEY_4 },
22 { 0x14, KEY_5 },
23 { 0x34, KEY_6 },
24 { 0x2c, KEY_7 },
25 { 0x1c, KEY_8 },
26 { 0x3c, KEY_9 },
27 { 0x22, KEY_0 },
28
29 { 0x20, KEY_TV }, /* TV/FM */
30 { 0x10, KEY_CD }, /* CD */
31 { 0x30, KEY_TEXT }, /* TELETEXT */
32 { 0x00, KEY_POWER }, /* POWER */
33
34 { 0x08, KEY_VIDEO }, /* VIDEO */
35 { 0x04, KEY_AUDIO }, /* AUDIO */
36 { 0x0c, KEY_ZOOM }, /* FULL SCREEN */
37
38 { 0x12, KEY_SUBTITLE }, /* DISPLAY */
39 { 0x32, KEY_REWIND }, /* LOOP */
40 { 0x02, KEY_PRINT }, /* PREVIEW */
41
42 { 0x2a, KEY_SEARCH }, /* AUTOSCAN */
43 { 0x1a, KEY_SLEEP }, /* FREEZE */
44 { 0x3a, KEY_CAMERA }, /* SNAPSHOT */
45 { 0x0a, KEY_MUTE }, /* MUTE */
46
47 { 0x26, KEY_RECORD }, /* RECORD */
48 { 0x16, KEY_PAUSE }, /* PAUSE */
49 { 0x36, KEY_STOP }, /* STOP */
50 { 0x06, KEY_PLAY }, /* PLAY */
51
52 { 0x2e, KEY_RED }, /* RED */
53 { 0x21, KEY_GREEN }, /* GREEN */
54 { 0x0e, KEY_YELLOW }, /* YELLOW */
55 { 0x01, KEY_BLUE }, /* BLUE */
56
57 { 0x1e, KEY_VOLUMEDOWN }, /* VOLUME- */
58 { 0x3e, KEY_VOLUMEUP }, /* VOLUME+ */
59 { 0x11, KEY_CHANNELDOWN }, /* CHANNEL/PAGE- */
60 { 0x31, KEY_CHANNELUP } /* CHANNEL/PAGE+ */
61};
62
63static struct rc_map_list avermedia_map = {
64 .map = {
65 .scan = avermedia,
66 .size = ARRAY_SIZE(avermedia),
67 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
68 .name = RC_MAP_AVERMEDIA,
69 }
70};
71
72static int __init init_rc_map_avermedia(void)
73{
74 return rc_map_register(&avermedia_map);
75}
76
77static void __exit exit_rc_map_avermedia(void)
78{
79 rc_map_unregister(&avermedia_map);
80}
81
82module_init(init_rc_map_avermedia)
83module_exit(exit_rc_map_avermedia)
84
85MODULE_LICENSE("GPL");
86MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c
new file mode 100644
index 000000000000..32e94988dc94
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avertv-303.c
@@ -0,0 +1,85 @@
1/* avertv-303.h - Keytable for avertv_303 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* AVERTV STUDIO 303 Remote */
16
17static struct rc_map_table avertv_303[] = {
18 { 0x2a, KEY_1 },
19 { 0x32, KEY_2 },
20 { 0x3a, KEY_3 },
21 { 0x4a, KEY_4 },
22 { 0x52, KEY_5 },
23 { 0x5a, KEY_6 },
24 { 0x6a, KEY_7 },
25 { 0x72, KEY_8 },
26 { 0x7a, KEY_9 },
27 { 0x0e, KEY_0 },
28
29 { 0x02, KEY_POWER },
30 { 0x22, KEY_VIDEO },
31 { 0x42, KEY_AUDIO },
32 { 0x62, KEY_ZOOM },
33 { 0x0a, KEY_TV },
34 { 0x12, KEY_CD },
35 { 0x1a, KEY_TEXT },
36
37 { 0x16, KEY_SUBTITLE },
38 { 0x1e, KEY_REWIND },
39 { 0x06, KEY_PRINT },
40
41 { 0x2e, KEY_SEARCH },
42 { 0x36, KEY_SLEEP },
43 { 0x3e, KEY_SHUFFLE },
44 { 0x26, KEY_MUTE },
45
46 { 0x4e, KEY_RECORD },
47 { 0x56, KEY_PAUSE },
48 { 0x5e, KEY_STOP },
49 { 0x46, KEY_PLAY },
50
51 { 0x6e, KEY_RED },
52 { 0x0b, KEY_GREEN },
53 { 0x66, KEY_YELLOW },
54 { 0x03, KEY_BLUE },
55
56 { 0x76, KEY_LEFT },
57 { 0x7e, KEY_RIGHT },
58 { 0x13, KEY_DOWN },
59 { 0x1b, KEY_UP },
60};
61
62static struct rc_map_list avertv_303_map = {
63 .map = {
64 .scan = avertv_303,
65 .size = ARRAY_SIZE(avertv_303),
66 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
67 .name = RC_MAP_AVERTV_303,
68 }
69};
70
71static int __init init_rc_map_avertv_303(void)
72{
73 return rc_map_register(&avertv_303_map);
74}
75
76static void __exit exit_rc_map_avertv_303(void)
77{
78 rc_map_unregister(&avertv_303_map);
79}
80
81module_init(init_rc_map_avertv_303)
82module_exit(exit_rc_map_avertv_303)
83
84MODULE_LICENSE("GPL");
85MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
new file mode 100644
index 000000000000..c3f6d62ac892
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
@@ -0,0 +1,102 @@
1/*
2 * TwinHan AzureWave AD-TU700(704J) remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23static struct rc_map_table azurewave_ad_tu700[] = {
24 { 0x0000, KEY_TAB }, /* Tab */
25 { 0x0001, KEY_2 },
26 { 0x0002, KEY_CHANNELDOWN },
27 { 0x0003, KEY_1 },
28 { 0x0004, KEY_MENU }, /* Record List */
29 { 0x0005, KEY_CHANNELUP },
30 { 0x0006, KEY_3 },
31 { 0x0007, KEY_SLEEP }, /* Hibernate */
32 { 0x0008, KEY_VIDEO }, /* A/V */
33 { 0x0009, KEY_4 },
34 { 0x000a, KEY_VOLUMEDOWN },
35 { 0x000c, KEY_CANCEL }, /* Cancel */
36 { 0x000d, KEY_7 },
37 { 0x000e, KEY_AGAIN }, /* Recall */
38 { 0x000f, KEY_TEXT }, /* Teletext */
39 { 0x0010, KEY_MUTE },
40 { 0x0011, KEY_RECORD },
41 { 0x0012, KEY_FASTFORWARD }, /* FF >> */
42 { 0x0013, KEY_BACK }, /* Back */
43 { 0x0014, KEY_PLAY },
44 { 0x0015, KEY_0 },
45 { 0x0016, KEY_POWER2 }, /* [red power button] */
46 { 0x0017, KEY_FAVORITES }, /* Favorite List */
47 { 0x0018, KEY_RED },
48 { 0x0019, KEY_8 },
49 { 0x001a, KEY_STOP },
50 { 0x001b, KEY_9 },
51 { 0x001c, KEY_EPG }, /* Info/EPG */
52 { 0x001d, KEY_5 },
53 { 0x001e, KEY_VOLUMEUP },
54 { 0x001f, KEY_6 },
55 { 0x0040, KEY_REWIND }, /* FR << */
56 { 0x0041, KEY_PREVIOUS }, /* Replay */
57 { 0x0042, KEY_NEXT }, /* Skip */
58 { 0x0043, KEY_SUBTITLE }, /* Subtitle / CC */
59 { 0x0045, KEY_KPPLUS }, /* Zoom+ */
60 { 0x0046, KEY_KPMINUS }, /* Zoom- */
61 { 0x0047, KEY_NEW }, /* PIP */
62 { 0x0048, KEY_INFO }, /* Preview */
63 { 0x0049, KEY_MODE }, /* L/R */
64 { 0x004a, KEY_CLEAR }, /* Clear */
65 { 0x004b, KEY_UP }, /* up arrow */
66 { 0x004c, KEY_PAUSE },
67 { 0x004d, KEY_ZOOM }, /* Full Screen */
68 { 0x004e, KEY_LEFT }, /* left arrow */
69 { 0x004f, KEY_OK }, /* Enter / ok */
70 { 0x0050, KEY_LANGUAGE }, /* SAP */
71 { 0x0051, KEY_DOWN }, /* down arrow */
72 { 0x0052, KEY_RIGHT }, /* right arrow */
73 { 0x0053, KEY_GREEN },
74 { 0x0054, KEY_CAMERA }, /* Capture */
75 { 0x005e, KEY_YELLOW },
76 { 0x005f, KEY_BLUE },
77};
78
79static struct rc_map_list azurewave_ad_tu700_map = {
80 .map = {
81 .scan = azurewave_ad_tu700,
82 .size = ARRAY_SIZE(azurewave_ad_tu700),
83 .rc_type = RC_TYPE_NEC,
84 .name = RC_MAP_AZUREWAVE_AD_TU700,
85 }
86};
87
88static int __init init_rc_map_azurewave_ad_tu700(void)
89{
90 return rc_map_register(&azurewave_ad_tu700_map);
91}
92
93static void __exit exit_rc_map_azurewave_ad_tu700(void)
94{
95 rc_map_unregister(&azurewave_ad_tu700_map);
96}
97
98module_init(init_rc_map_azurewave_ad_tu700)
99module_exit(exit_rc_map_azurewave_ad_tu700)
100
101MODULE_LICENSE("GPL");
102MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c
new file mode 100644
index 000000000000..4b787fa94f08
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-behold-columbus.c
@@ -0,0 +1,108 @@
1/* behold-columbus.h - Keytable for behold_columbus Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Beholder Intl. Ltd. 2008
16 * Dmitry Belimov d.belimov@google.com
17 * Keytable is used by BeholdTV Columbus
18 * The "ascii-art picture" below (in comments, first row
19 * is the keycode in hex, and subsequent row(s) shows
20 * the button labels (several variants when appropriate)
21 * helps to descide which keycodes to assign to the buttons.
22 */
23
24static struct rc_map_table behold_columbus[] = {
25
26 /* 0x13 0x11 0x1C 0x12 *
27 * Mute Source TV/FM Power *
28 * */
29
30 { 0x13, KEY_MUTE },
31 { 0x11, KEY_PROPS },
32 { 0x1C, KEY_TUNER }, /* KEY_TV/KEY_RADIO */
33 { 0x12, KEY_POWER },
34
35 /* 0x01 0x02 0x03 0x0D *
36 * 1 2 3 Stereo *
37 * *
38 * 0x04 0x05 0x06 0x19 *
39 * 4 5 6 Snapshot *
40 * *
41 * 0x07 0x08 0x09 0x10 *
42 * 7 8 9 Zoom *
43 * */
44 { 0x01, KEY_1 },
45 { 0x02, KEY_2 },
46 { 0x03, KEY_3 },
47 { 0x0D, KEY_SETUP }, /* Setup key */
48 { 0x04, KEY_4 },
49 { 0x05, KEY_5 },
50 { 0x06, KEY_6 },
51 { 0x19, KEY_CAMERA }, /* Snapshot key */
52 { 0x07, KEY_7 },
53 { 0x08, KEY_8 },
54 { 0x09, KEY_9 },
55 { 0x10, KEY_ZOOM },
56
57 /* 0x0A 0x00 0x0B 0x0C *
58 * RECALL 0 ChannelUp VolumeUp *
59 * */
60 { 0x0A, KEY_AGAIN },
61 { 0x00, KEY_0 },
62 { 0x0B, KEY_CHANNELUP },
63 { 0x0C, KEY_VOLUMEUP },
64
65 /* 0x1B 0x1D 0x15 0x18 *
66 * Timeshift Record ChannelDown VolumeDown *
67 * */
68
69 { 0x1B, KEY_TIME },
70 { 0x1D, KEY_RECORD },
71 { 0x15, KEY_CHANNELDOWN },
72 { 0x18, KEY_VOLUMEDOWN },
73
74 /* 0x0E 0x1E 0x0F 0x1A *
75 * Stop Pause Previouse Next *
76 * */
77
78 { 0x0E, KEY_STOP },
79 { 0x1E, KEY_PAUSE },
80 { 0x0F, KEY_PREVIOUS },
81 { 0x1A, KEY_NEXT },
82
83};
84
85static struct rc_map_list behold_columbus_map = {
86 .map = {
87 .scan = behold_columbus,
88 .size = ARRAY_SIZE(behold_columbus),
89 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
90 .name = RC_MAP_BEHOLD_COLUMBUS,
91 }
92};
93
94static int __init init_rc_map_behold_columbus(void)
95{
96 return rc_map_register(&behold_columbus_map);
97}
98
99static void __exit exit_rc_map_behold_columbus(void)
100{
101 rc_map_unregister(&behold_columbus_map);
102}
103
104module_init(init_rc_map_behold_columbus)
105module_exit(exit_rc_map_behold_columbus)
106
107MODULE_LICENSE("GPL");
108MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
new file mode 100644
index 000000000000..0ee1f149364c
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -0,0 +1,141 @@
1/* behold.h - Keytable for behold Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 * Igor Kuznetsov <igk72@ya.ru>
17 * Andrey J. Melnikov <temnota@kmv.ru>
18 *
19 * Keytable is used by BeholdTV 60x series, M6 series at
20 * least, and probably other cards too.
21 * The "ascii-art picture" below (in comments, first row
22 * is the keycode in hex, and subsequent row(s) shows
23 * the button labels (several variants when appropriate)
24 * helps to descide which keycodes to assign to the buttons.
25 */
26
27static struct rc_map_table behold[] = {
28
29 /* 0x1c 0x12 *
30 * TV/FM POWER *
31 * */
32 { 0x6b861c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */
33 { 0x6b8612, KEY_POWER },
34
35 /* 0x01 0x02 0x03 *
36 * 1 2 3 *
37 * *
38 * 0x04 0x05 0x06 *
39 * 4 5 6 *
40 * *
41 * 0x07 0x08 0x09 *
42 * 7 8 9 *
43 * */
44 { 0x6b8601, KEY_1 },
45 { 0x6b8602, KEY_2 },
46 { 0x6b8603, KEY_3 },
47 { 0x6b8604, KEY_4 },
48 { 0x6b8605, KEY_5 },
49 { 0x6b8606, KEY_6 },
50 { 0x6b8607, KEY_7 },
51 { 0x6b8608, KEY_8 },
52 { 0x6b8609, KEY_9 },
53
54 /* 0x0a 0x00 0x17 *
55 * RECALL 0 MODE *
56 * */
57 { 0x6b860a, KEY_AGAIN },
58 { 0x6b8600, KEY_0 },
59 { 0x6b8617, KEY_MODE },
60
61 /* 0x14 0x10 *
62 * ASPECT FULLSCREEN *
63 * */
64 { 0x6b8614, KEY_SCREEN },
65 { 0x6b8610, KEY_ZOOM },
66
67 /* 0x0b *
68 * Up *
69 * *
70 * 0x18 0x16 0x0c *
71 * Left Ok Right *
72 * *
73 * 0x015 *
74 * Down *
75 * */
76 { 0x6b860b, KEY_CHANNELUP },
77 { 0x6b8618, KEY_VOLUMEDOWN },
78 { 0x6b8616, KEY_OK }, /* XXX KEY_ENTER */
79 { 0x6b860c, KEY_VOLUMEUP },
80 { 0x6b8615, KEY_CHANNELDOWN },
81
82 /* 0x11 0x0d *
83 * MUTE INFO *
84 * */
85 { 0x6b8611, KEY_MUTE },
86 { 0x6b860d, KEY_INFO },
87
88 /* 0x0f 0x1b 0x1a *
89 * RECORD PLAY/PAUSE STOP *
90 * *
91 * 0x0e 0x1f 0x1e *
92 *TELETEXT AUDIO SOURCE *
93 * RED YELLOW *
94 * */
95 { 0x6b860f, KEY_RECORD },
96 { 0x6b861b, KEY_PLAYPAUSE },
97 { 0x6b861a, KEY_STOP },
98 { 0x6b860e, KEY_TEXT },
99 { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */
100 { 0x6b861e, KEY_YELLOW }, /*XXX KEY_SOURCE */
101
102 /* 0x1d 0x13 0x19 *
103 * SLEEP PREVIEW DVB *
104 * GREEN BLUE *
105 * */
106 { 0x6b861d, KEY_SLEEP },
107 { 0x6b8613, KEY_GREEN },
108 { 0x6b8619, KEY_BLUE }, /* XXX KEY_SAT */
109
110 /* 0x58 0x5c *
111 * FREEZE SNAPSHOT *
112 * */
113 { 0x6b8658, KEY_SLOW },
114 { 0x6b865c, KEY_CAMERA },
115
116};
117
118static struct rc_map_list behold_map = {
119 .map = {
120 .scan = behold,
121 .size = ARRAY_SIZE(behold),
122 .rc_type = RC_TYPE_NEC,
123 .name = RC_MAP_BEHOLD,
124 }
125};
126
127static int __init init_rc_map_behold(void)
128{
129 return rc_map_register(&behold_map);
130}
131
132static void __exit exit_rc_map_behold(void)
133{
134 rc_map_unregister(&behold_map);
135}
136
137module_init(init_rc_map_behold)
138module_exit(exit_rc_map_behold)
139
140MODULE_LICENSE("GPL");
141MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c
new file mode 100644
index 000000000000..97fc3862f608
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c
@@ -0,0 +1,92 @@
1/* budget-ci-old.h - Keytable for budget_ci_old Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* From reading the following remotes:
16 * Zenith Universal 7 / TV Mode 807 / VCR Mode 837
17 * Hauppauge (from NOVA-CI-s box product)
18 * This is a "middle of the road" approach, differences are noted
19 */
20
21static struct rc_map_table budget_ci_old[] = {
22 { 0x00, KEY_0 },
23 { 0x01, KEY_1 },
24 { 0x02, KEY_2 },
25 { 0x03, KEY_3 },
26 { 0x04, KEY_4 },
27 { 0x05, KEY_5 },
28 { 0x06, KEY_6 },
29 { 0x07, KEY_7 },
30 { 0x08, KEY_8 },
31 { 0x09, KEY_9 },
32 { 0x0a, KEY_ENTER },
33 { 0x0b, KEY_RED },
34 { 0x0c, KEY_POWER }, /* RADIO on Hauppauge */
35 { 0x0d, KEY_MUTE },
36 { 0x0f, KEY_A }, /* TV on Hauppauge */
37 { 0x10, KEY_VOLUMEUP },
38 { 0x11, KEY_VOLUMEDOWN },
39 { 0x14, KEY_B },
40 { 0x1c, KEY_UP },
41 { 0x1d, KEY_DOWN },
42 { 0x1e, KEY_OPTION }, /* RESERVED on Hauppauge */
43 { 0x1f, KEY_BREAK },
44 { 0x20, KEY_CHANNELUP },
45 { 0x21, KEY_CHANNELDOWN },
46 { 0x22, KEY_PREVIOUS }, /* Prev Ch on Zenith, SOURCE on Hauppauge */
47 { 0x24, KEY_RESTART },
48 { 0x25, KEY_OK },
49 { 0x26, KEY_CYCLEWINDOWS }, /* MINIMIZE on Hauppauge */
50 { 0x28, KEY_ENTER }, /* VCR mode on Zenith */
51 { 0x29, KEY_PAUSE },
52 { 0x2b, KEY_RIGHT },
53 { 0x2c, KEY_LEFT },
54 { 0x2e, KEY_MENU }, /* FULL SCREEN on Hauppauge */
55 { 0x30, KEY_SLOW },
56 { 0x31, KEY_PREVIOUS }, /* VCR mode on Zenith */
57 { 0x32, KEY_REWIND },
58 { 0x34, KEY_FASTFORWARD },
59 { 0x35, KEY_PLAY },
60 { 0x36, KEY_STOP },
61 { 0x37, KEY_RECORD },
62 { 0x38, KEY_TUNER }, /* TV/VCR on Zenith */
63 { 0x3a, KEY_C },
64 { 0x3c, KEY_EXIT },
65 { 0x3d, KEY_POWER2 },
66 { 0x3e, KEY_TUNER },
67};
68
69static struct rc_map_list budget_ci_old_map = {
70 .map = {
71 .scan = budget_ci_old,
72 .size = ARRAY_SIZE(budget_ci_old),
73 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
74 .name = RC_MAP_BUDGET_CI_OLD,
75 }
76};
77
78static int __init init_rc_map_budget_ci_old(void)
79{
80 return rc_map_register(&budget_ci_old_map);
81}
82
83static void __exit exit_rc_map_budget_ci_old(void)
84{
85 rc_map_unregister(&budget_ci_old_map);
86}
87
88module_init(init_rc_map_budget_ci_old)
89module_exit(exit_rc_map_budget_ci_old)
90
91MODULE_LICENSE("GPL");
92MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c
new file mode 100644
index 000000000000..284534b67e7d
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c
@@ -0,0 +1,84 @@
1/* cinergy-1400.h - Keytable for cinergy_1400 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Cinergy 1400 DVB-T */
16
17static struct rc_map_table cinergy_1400[] = {
18 { 0x01, KEY_POWER },
19 { 0x02, KEY_1 },
20 { 0x03, KEY_2 },
21 { 0x04, KEY_3 },
22 { 0x05, KEY_4 },
23 { 0x06, KEY_5 },
24 { 0x07, KEY_6 },
25 { 0x08, KEY_7 },
26 { 0x09, KEY_8 },
27 { 0x0a, KEY_9 },
28 { 0x0c, KEY_0 },
29
30 { 0x0b, KEY_VIDEO },
31 { 0x0d, KEY_REFRESH },
32 { 0x0e, KEY_SELECT },
33 { 0x0f, KEY_EPG },
34 { 0x10, KEY_UP },
35 { 0x11, KEY_LEFT },
36 { 0x12, KEY_OK },
37 { 0x13, KEY_RIGHT },
38 { 0x14, KEY_DOWN },
39 { 0x15, KEY_TEXT },
40 { 0x16, KEY_INFO },
41
42 { 0x17, KEY_RED },
43 { 0x18, KEY_GREEN },
44 { 0x19, KEY_YELLOW },
45 { 0x1a, KEY_BLUE },
46
47 { 0x1b, KEY_CHANNELUP },
48 { 0x1c, KEY_VOLUMEUP },
49 { 0x1d, KEY_MUTE },
50 { 0x1e, KEY_VOLUMEDOWN },
51 { 0x1f, KEY_CHANNELDOWN },
52
53 { 0x40, KEY_PAUSE },
54 { 0x4c, KEY_PLAY },
55 { 0x58, KEY_RECORD },
56 { 0x54, KEY_PREVIOUS },
57 { 0x48, KEY_STOP },
58 { 0x5c, KEY_NEXT },
59};
60
61static struct rc_map_list cinergy_1400_map = {
62 .map = {
63 .scan = cinergy_1400,
64 .size = ARRAY_SIZE(cinergy_1400),
65 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
66 .name = RC_MAP_CINERGY_1400,
67 }
68};
69
70static int __init init_rc_map_cinergy_1400(void)
71{
72 return rc_map_register(&cinergy_1400_map);
73}
74
75static void __exit exit_rc_map_cinergy_1400(void)
76{
77 rc_map_unregister(&cinergy_1400_map);
78}
79
80module_init(init_rc_map_cinergy_1400)
81module_exit(exit_rc_map_cinergy_1400)
82
83MODULE_LICENSE("GPL");
84MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c
new file mode 100644
index 000000000000..99520ff65b61
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-cinergy.c
@@ -0,0 +1,78 @@
1/* cinergy.h - Keytable for cinergy Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table cinergy[] = {
16 { 0x00, KEY_0 },
17 { 0x01, KEY_1 },
18 { 0x02, KEY_2 },
19 { 0x03, KEY_3 },
20 { 0x04, KEY_4 },
21 { 0x05, KEY_5 },
22 { 0x06, KEY_6 },
23 { 0x07, KEY_7 },
24 { 0x08, KEY_8 },
25 { 0x09, KEY_9 },
26
27 { 0x0a, KEY_POWER },
28 { 0x0b, KEY_PROG1 }, /* app */
29 { 0x0c, KEY_ZOOM }, /* zoom/fullscreen */
30 { 0x0d, KEY_CHANNELUP }, /* channel */
31 { 0x0e, KEY_CHANNELDOWN }, /* channel- */
32 { 0x0f, KEY_VOLUMEUP },
33 { 0x10, KEY_VOLUMEDOWN },
34 { 0x11, KEY_TUNER }, /* AV */
35 { 0x12, KEY_NUMLOCK }, /* -/-- */
36 { 0x13, KEY_AUDIO }, /* audio */
37 { 0x14, KEY_MUTE },
38 { 0x15, KEY_UP },
39 { 0x16, KEY_DOWN },
40 { 0x17, KEY_LEFT },
41 { 0x18, KEY_RIGHT },
42 { 0x19, BTN_LEFT, },
43 { 0x1a, BTN_RIGHT, },
44 { 0x1b, KEY_WWW }, /* text */
45 { 0x1c, KEY_REWIND },
46 { 0x1d, KEY_FORWARD },
47 { 0x1e, KEY_RECORD },
48 { 0x1f, KEY_PLAY },
49 { 0x20, KEY_PREVIOUSSONG },
50 { 0x21, KEY_NEXTSONG },
51 { 0x22, KEY_PAUSE },
52 { 0x23, KEY_STOP },
53};
54
55static struct rc_map_list cinergy_map = {
56 .map = {
57 .scan = cinergy,
58 .size = ARRAY_SIZE(cinergy),
59 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
60 .name = RC_MAP_CINERGY,
61 }
62};
63
64static int __init init_rc_map_cinergy(void)
65{
66 return rc_map_register(&cinergy_map);
67}
68
69static void __exit exit_rc_map_cinergy(void)
70{
71 rc_map_unregister(&cinergy_map);
72}
73
74module_init(init_rc_map_cinergy)
75module_exit(exit_rc_map_cinergy)
76
77MODULE_LICENSE("GPL");
78MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c
new file mode 100644
index 000000000000..c59851b203da
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c
@@ -0,0 +1,124 @@
1/* rc-dvb0700-big.c - Keytable for devices in dvb0700
2 *
3 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 *
5 * TODO: This table is a real mess, as it merges RC codes from several
6 * devices into a big table. It also has both RC-5 and NEC codes inside.
7 * It should be broken into small tables, and the protocols should properly
8 * be indentificated.
9 *
10 * The table were imported from dib0700_devices.c.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 */
17
18#include <media/rc-map.h>
19
20static struct rc_map_table dib0700_nec_table[] = {
21 /* Key codes for the Pixelview SBTVD remote */
22 { 0x8613, KEY_MUTE },
23 { 0x8612, KEY_POWER },
24 { 0x8601, KEY_1 },
25 { 0x8602, KEY_2 },
26 { 0x8603, KEY_3 },
27 { 0x8604, KEY_4 },
28 { 0x8605, KEY_5 },
29 { 0x8606, KEY_6 },
30 { 0x8607, KEY_7 },
31 { 0x8608, KEY_8 },
32 { 0x8609, KEY_9 },
33 { 0x8600, KEY_0 },
34 { 0x860d, KEY_CHANNELUP },
35 { 0x8619, KEY_CHANNELDOWN },
36 { 0x8610, KEY_VOLUMEUP },
37 { 0x860c, KEY_VOLUMEDOWN },
38
39 { 0x860a, KEY_CAMERA },
40 { 0x860b, KEY_ZOOM },
41 { 0x861b, KEY_BACKSPACE },
42 { 0x8615, KEY_ENTER },
43
44 { 0x861d, KEY_UP },
45 { 0x861e, KEY_DOWN },
46 { 0x860e, KEY_LEFT },
47 { 0x860f, KEY_RIGHT },
48
49 { 0x8618, KEY_RECORD },
50 { 0x861a, KEY_STOP },
51
52 /* Key codes for the EvolutePC TVWay+ remote */
53 { 0x7a00, KEY_MENU },
54 { 0x7a01, KEY_RECORD },
55 { 0x7a02, KEY_PLAY },
56 { 0x7a03, KEY_STOP },
57 { 0x7a10, KEY_CHANNELUP },
58 { 0x7a11, KEY_CHANNELDOWN },
59 { 0x7a12, KEY_VOLUMEUP },
60 { 0x7a13, KEY_VOLUMEDOWN },
61 { 0x7a40, KEY_POWER },
62 { 0x7a41, KEY_MUTE },
63
64 /* Key codes for the Elgato EyeTV Diversity silver remote */
65 { 0x4501, KEY_POWER },
66 { 0x4502, KEY_MUTE },
67 { 0x4503, KEY_1 },
68 { 0x4504, KEY_2 },
69 { 0x4505, KEY_3 },
70 { 0x4506, KEY_4 },
71 { 0x4507, KEY_5 },
72 { 0x4508, KEY_6 },
73 { 0x4509, KEY_7 },
74 { 0x450a, KEY_8 },
75 { 0x450b, KEY_9 },
76 { 0x450c, KEY_LAST },
77 { 0x450d, KEY_0 },
78 { 0x450e, KEY_ENTER },
79 { 0x450f, KEY_RED },
80 { 0x4510, KEY_CHANNELUP },
81 { 0x4511, KEY_GREEN },
82 { 0x4512, KEY_VOLUMEDOWN },
83 { 0x4513, KEY_OK },
84 { 0x4514, KEY_VOLUMEUP },
85 { 0x4515, KEY_YELLOW },
86 { 0x4516, KEY_CHANNELDOWN },
87 { 0x4517, KEY_BLUE },
88 { 0x4518, KEY_LEFT }, /* Skip backwards */
89 { 0x4519, KEY_PLAYPAUSE },
90 { 0x451a, KEY_RIGHT }, /* Skip forward */
91 { 0x451b, KEY_REWIND },
92 { 0x451c, KEY_L }, /* Live */
93 { 0x451d, KEY_FASTFORWARD },
94 { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
95 { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
96 { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
97 { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */
98 { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
99};
100
101static struct rc_map_list dib0700_nec_map = {
102 .map = {
103 .scan = dib0700_nec_table,
104 .size = ARRAY_SIZE(dib0700_nec_table),
105 .rc_type = RC_TYPE_NEC,
106 .name = RC_MAP_DIB0700_NEC_TABLE,
107 }
108};
109
110static int __init init_rc_map(void)
111{
112 return rc_map_register(&dib0700_nec_map);
113}
114
115static void __exit exit_rc_map(void)
116{
117 rc_map_unregister(&dib0700_nec_map);
118}
119
120module_init(init_rc_map)
121module_exit(exit_rc_map)
122
123MODULE_LICENSE("GPL");
124MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
new file mode 100644
index 000000000000..4af12e45dfba
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
@@ -0,0 +1,235 @@
1/* rc-dvb0700-big.c - Keytable for devices in dvb0700
2 *
3 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 *
5 * TODO: This table is a real mess, as it merges RC codes from several
6 * devices into a big table. It also has both RC-5 and NEC codes inside.
7 * It should be broken into small tables, and the protocols should properly
8 * be indentificated.
9 *
10 * The table were imported from dib0700_devices.c.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 */
17
18#include <media/rc-map.h>
19
20static struct rc_map_table dib0700_rc5_table[] = {
21 /* Key codes for the tiny Pinnacle remote*/
22 { 0x0700, KEY_MUTE },
23 { 0x0701, KEY_MENU }, /* Pinnacle logo */
24 { 0x0739, KEY_POWER },
25 { 0x0703, KEY_VOLUMEUP },
26 { 0x0709, KEY_VOLUMEDOWN },
27 { 0x0706, KEY_CHANNELUP },
28 { 0x070c, KEY_CHANNELDOWN },
29 { 0x070f, KEY_1 },
30 { 0x0715, KEY_2 },
31 { 0x0710, KEY_3 },
32 { 0x0718, KEY_4 },
33 { 0x071b, KEY_5 },
34 { 0x071e, KEY_6 },
35 { 0x0711, KEY_7 },
36 { 0x0721, KEY_8 },
37 { 0x0712, KEY_9 },
38 { 0x0727, KEY_0 },
39 { 0x0724, KEY_SCREEN }, /* 'Square' key */
40 { 0x072a, KEY_TEXT }, /* 'T' key */
41 { 0x072d, KEY_REWIND },
42 { 0x0730, KEY_PLAY },
43 { 0x0733, KEY_FASTFORWARD },
44 { 0x0736, KEY_RECORD },
45 { 0x073c, KEY_STOP },
46 { 0x073f, KEY_CANCEL }, /* '?' key */
47
48 /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
49 { 0xeb01, KEY_POWER },
50 { 0xeb02, KEY_1 },
51 { 0xeb03, KEY_2 },
52 { 0xeb04, KEY_3 },
53 { 0xeb05, KEY_4 },
54 { 0xeb06, KEY_5 },
55 { 0xeb07, KEY_6 },
56 { 0xeb08, KEY_7 },
57 { 0xeb09, KEY_8 },
58 { 0xeb0a, KEY_9 },
59 { 0xeb0b, KEY_VIDEO },
60 { 0xeb0c, KEY_0 },
61 { 0xeb0d, KEY_REFRESH },
62 { 0xeb0f, KEY_EPG },
63 { 0xeb10, KEY_UP },
64 { 0xeb11, KEY_LEFT },
65 { 0xeb12, KEY_OK },
66 { 0xeb13, KEY_RIGHT },
67 { 0xeb14, KEY_DOWN },
68 { 0xeb16, KEY_INFO },
69 { 0xeb17, KEY_RED },
70 { 0xeb18, KEY_GREEN },
71 { 0xeb19, KEY_YELLOW },
72 { 0xeb1a, KEY_BLUE },
73 { 0xeb1b, KEY_CHANNELUP },
74 { 0xeb1c, KEY_VOLUMEUP },
75 { 0xeb1d, KEY_MUTE },
76 { 0xeb1e, KEY_VOLUMEDOWN },
77 { 0xeb1f, KEY_CHANNELDOWN },
78 { 0xeb40, KEY_PAUSE },
79 { 0xeb41, KEY_HOME },
80 { 0xeb42, KEY_MENU }, /* DVD Menu */
81 { 0xeb43, KEY_SUBTITLE },
82 { 0xeb44, KEY_TEXT }, /* Teletext */
83 { 0xeb45, KEY_DELETE },
84 { 0xeb46, KEY_TV },
85 { 0xeb47, KEY_DVD },
86 { 0xeb48, KEY_STOP },
87 { 0xeb49, KEY_VIDEO },
88 { 0xeb4a, KEY_AUDIO }, /* Music */
89 { 0xeb4b, KEY_SCREEN }, /* Pic */
90 { 0xeb4c, KEY_PLAY },
91 { 0xeb4d, KEY_BACK },
92 { 0xeb4e, KEY_REWIND },
93 { 0xeb4f, KEY_FASTFORWARD },
94 { 0xeb54, KEY_PREVIOUS },
95 { 0xeb58, KEY_RECORD },
96 { 0xeb5c, KEY_NEXT },
97
98 /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
99 { 0x1e00, KEY_0 },
100 { 0x1e01, KEY_1 },
101 { 0x1e02, KEY_2 },
102 { 0x1e03, KEY_3 },
103 { 0x1e04, KEY_4 },
104 { 0x1e05, KEY_5 },
105 { 0x1e06, KEY_6 },
106 { 0x1e07, KEY_7 },
107 { 0x1e08, KEY_8 },
108 { 0x1e09, KEY_9 },
109 { 0x1e0a, KEY_KPASTERISK },
110 { 0x1e0b, KEY_RED },
111 { 0x1e0c, KEY_RADIO },
112 { 0x1e0d, KEY_MENU },
113 { 0x1e0e, KEY_GRAVE }, /* # */
114 { 0x1e0f, KEY_MUTE },
115 { 0x1e10, KEY_VOLUMEUP },
116 { 0x1e11, KEY_VOLUMEDOWN },
117 { 0x1e12, KEY_CHANNEL },
118 { 0x1e14, KEY_UP },
119 { 0x1e15, KEY_DOWN },
120 { 0x1e16, KEY_LEFT },
121 { 0x1e17, KEY_RIGHT },
122 { 0x1e18, KEY_VIDEO },
123 { 0x1e19, KEY_AUDIO },
124 { 0x1e1a, KEY_MEDIA },
125 { 0x1e1b, KEY_EPG },
126 { 0x1e1c, KEY_TV },
127 { 0x1e1e, KEY_NEXT },
128 { 0x1e1f, KEY_BACK },
129 { 0x1e20, KEY_CHANNELUP },
130 { 0x1e21, KEY_CHANNELDOWN },
131 { 0x1e24, KEY_LAST }, /* Skip backwards */
132 { 0x1e25, KEY_OK },
133 { 0x1e29, KEY_BLUE},
134 { 0x1e2e, KEY_GREEN },
135 { 0x1e30, KEY_PAUSE },
136 { 0x1e32, KEY_REWIND },
137 { 0x1e34, KEY_FASTFORWARD },
138 { 0x1e35, KEY_PLAY },
139 { 0x1e36, KEY_STOP },
140 { 0x1e37, KEY_RECORD },
141 { 0x1e38, KEY_YELLOW },
142 { 0x1e3b, KEY_GOTO },
143 { 0x1e3d, KEY_POWER },
144
145 /* Key codes for the Leadtek Winfast DTV Dongle */
146 { 0x0042, KEY_POWER },
147 { 0x077c, KEY_TUNER },
148 { 0x0f4e, KEY_PRINT }, /* PREVIEW */
149 { 0x0840, KEY_SCREEN }, /* full screen toggle*/
150 { 0x0f71, KEY_DOT }, /* frequency */
151 { 0x0743, KEY_0 },
152 { 0x0c41, KEY_1 },
153 { 0x0443, KEY_2 },
154 { 0x0b7f, KEY_3 },
155 { 0x0e41, KEY_4 },
156 { 0x0643, KEY_5 },
157 { 0x097f, KEY_6 },
158 { 0x0d7e, KEY_7 },
159 { 0x057c, KEY_8 },
160 { 0x0a40, KEY_9 },
161 { 0x0e4e, KEY_CLEAR },
162 { 0x047c, KEY_CHANNEL }, /* show channel number */
163 { 0x0f41, KEY_LAST }, /* recall */
164 { 0x0342, KEY_MUTE },
165 { 0x064c, KEY_RESERVED }, /* PIP button*/
166 { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
167 { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
168 { 0x0b70, KEY_RECORD },
169 { 0x037d, KEY_VOLUMEUP },
170 { 0x017d, KEY_VOLUMEDOWN },
171 { 0x0242, KEY_CHANNELUP },
172 { 0x007d, KEY_CHANNELDOWN },
173
174 /* Key codes for Nova-TD "credit card" remote control. */
175 { 0x1d00, KEY_0 },
176 { 0x1d01, KEY_1 },
177 { 0x1d02, KEY_2 },
178 { 0x1d03, KEY_3 },
179 { 0x1d04, KEY_4 },
180 { 0x1d05, KEY_5 },
181 { 0x1d06, KEY_6 },
182 { 0x1d07, KEY_7 },
183 { 0x1d08, KEY_8 },
184 { 0x1d09, KEY_9 },
185 { 0x1d0a, KEY_TEXT },
186 { 0x1d0d, KEY_MENU },
187 { 0x1d0f, KEY_MUTE },
188 { 0x1d10, KEY_VOLUMEUP },
189 { 0x1d11, KEY_VOLUMEDOWN },
190 { 0x1d12, KEY_CHANNEL },
191 { 0x1d14, KEY_UP },
192 { 0x1d15, KEY_DOWN },
193 { 0x1d16, KEY_LEFT },
194 { 0x1d17, KEY_RIGHT },
195 { 0x1d1c, KEY_TV },
196 { 0x1d1e, KEY_NEXT },
197 { 0x1d1f, KEY_BACK },
198 { 0x1d20, KEY_CHANNELUP },
199 { 0x1d21, KEY_CHANNELDOWN },
200 { 0x1d24, KEY_LAST },
201 { 0x1d25, KEY_OK },
202 { 0x1d30, KEY_PAUSE },
203 { 0x1d32, KEY_REWIND },
204 { 0x1d34, KEY_FASTFORWARD },
205 { 0x1d35, KEY_PLAY },
206 { 0x1d36, KEY_STOP },
207 { 0x1d37, KEY_RECORD },
208 { 0x1d3b, KEY_GOTO },
209 { 0x1d3d, KEY_POWER },
210};
211
212static struct rc_map_list dib0700_rc5_map = {
213 .map = {
214 .scan = dib0700_rc5_table,
215 .size = ARRAY_SIZE(dib0700_rc5_table),
216 .rc_type = RC_TYPE_RC5,
217 .name = RC_MAP_DIB0700_RC5_TABLE,
218 }
219};
220
221static int __init init_rc_map(void)
222{
223 return rc_map_register(&dib0700_rc5_map);
224}
225
226static void __exit exit_rc_map(void)
227{
228 rc_map_unregister(&dib0700_rc5_map);
229}
230
231module_init(init_rc_map)
232module_exit(exit_rc_map)
233
234MODULE_LICENSE("GPL");
235MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
new file mode 100644
index 000000000000..f68b450f5593
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
@@ -0,0 +1,98 @@
1/*
2 * DigitalNow TinyTwin remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23static struct rc_map_table digitalnow_tinytwin[] = {
24 { 0x0000, KEY_MUTE }, /* [symbol speaker] */
25 { 0x0001, KEY_VOLUMEUP },
26 { 0x0002, KEY_POWER2 }, /* TV [power button] */
27 { 0x0003, KEY_2 },
28 { 0x0004, KEY_3 },
29 { 0x0005, KEY_4 },
30 { 0x0006, KEY_6 },
31 { 0x0007, KEY_7 },
32 { 0x0008, KEY_8 },
33 { 0x0009, KEY_NUMERIC_STAR }, /* [*] */
34 { 0x000a, KEY_0 },
35 { 0x000b, KEY_NUMERIC_POUND }, /* [#] */
36 { 0x000c, KEY_RIGHT }, /* [right arrow] */
37 { 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */
38 { 0x000e, KEY_RED }, /* [red] Videos */
39 { 0x0010, KEY_POWER }, /* PC [power button] */
40 { 0x0011, KEY_YELLOW }, /* [yellow] Pictures */
41 { 0x0012, KEY_DOWN }, /* [down arrow] */
42 { 0x0013, KEY_GREEN }, /* [green] Music */
43 { 0x0014, KEY_CYCLEWINDOWS }, /* BACK */
44 { 0x0015, KEY_FAVORITES }, /* MORE */
45 { 0x0016, KEY_UP }, /* [up arrow] */
46 { 0x0017, KEY_LEFT }, /* [left arrow] */
47 { 0x0018, KEY_OK }, /* OK */
48 { 0x0019, KEY_BLUE }, /* [blue] MyTV */
49 { 0x001a, KEY_REWIND }, /* REW [<<] */
50 { 0x001b, KEY_PLAY }, /* PLAY */
51 { 0x001c, KEY_5 },
52 { 0x001d, KEY_9 },
53 { 0x001e, KEY_VOLUMEDOWN },
54 { 0x001f, KEY_1 },
55 { 0x0040, KEY_STOP }, /* STOP */
56 { 0x0042, KEY_PAUSE }, /* PAUSE */
57 { 0x0043, KEY_SCREEN }, /* Aspect */
58 { 0x0044, KEY_FORWARD }, /* FWD [>>] */
59 { 0x0045, KEY_NEXT }, /* SKIP */
60 { 0x0048, KEY_RECORD }, /* RECORD */
61 { 0x0049, KEY_VIDEO }, /* RTV */
62 { 0x004a, KEY_EPG }, /* Guide */
63 { 0x004b, KEY_CHANNELUP },
64 { 0x004c, KEY_HELP }, /* Help */
65 { 0x004d, KEY_RADIO }, /* Radio */
66 { 0x004f, KEY_CHANNELDOWN },
67 { 0x0050, KEY_DVD }, /* DVD */
68 { 0x0051, KEY_AUDIO }, /* Audio */
69 { 0x0052, KEY_TITLE }, /* Title */
70 { 0x0053, KEY_NEW }, /* [symbol PIP?] */
71 { 0x0057, KEY_MENU }, /* Mouse */
72 { 0x005a, KEY_PREVIOUS }, /* REPLAY */
73};
74
75static struct rc_map_list digitalnow_tinytwin_map = {
76 .map = {
77 .scan = digitalnow_tinytwin,
78 .size = ARRAY_SIZE(digitalnow_tinytwin),
79 .rc_type = RC_TYPE_NEC,
80 .name = RC_MAP_DIGITALNOW_TINYTWIN,
81 }
82};
83
84static int __init init_rc_map_digitalnow_tinytwin(void)
85{
86 return rc_map_register(&digitalnow_tinytwin_map);
87}
88
89static void __exit exit_rc_map_digitalnow_tinytwin(void)
90{
91 rc_map_unregister(&digitalnow_tinytwin_map);
92}
93
94module_init(init_rc_map_digitalnow_tinytwin)
95module_exit(exit_rc_map_digitalnow_tinytwin)
96
97MODULE_LICENSE("GPL");
98MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c
new file mode 100644
index 000000000000..21d49871f2a3
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-digittrade.c
@@ -0,0 +1,82 @@
1/*
2 * Digittrade DVB-T USB Stick remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23/* Digittrade DVB-T USB Stick remote controller. */
24/* Imported from af9015.h.
25 Initial keytable was from Alain Kalker <miki@dds.nl> */
26
27/* Digittrade DVB-T USB Stick */
28static struct rc_map_table digittrade[] = {
29 { 0x0000, KEY_9 },
30 { 0x0001, KEY_EPG }, /* EPG */
31 { 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */
32 { 0x0003, KEY_TEXT }, /* TELETEXT */
33 { 0x0004, KEY_8 },
34 { 0x0005, KEY_MUTE }, /* MUTE */
35 { 0x0006, KEY_POWER2 }, /* POWER */
36 { 0x0009, KEY_ZOOM }, /* FULLSCREEN */
37 { 0x000a, KEY_RECORD }, /* RECORD */
38 { 0x000d, KEY_SUBTITLE }, /* SUBTITLE */
39 { 0x000e, KEY_STOP }, /* STOP */
40 { 0x0010, KEY_OK }, /* RETURN */
41 { 0x0011, KEY_2 },
42 { 0x0012, KEY_4 },
43 { 0x0015, KEY_3 },
44 { 0x0016, KEY_5 },
45 { 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */
46 { 0x0019, KEY_CHANNELUP }, /* CH Up */
47 { 0x001a, KEY_PAUSE }, /* PAUSE */
48 { 0x001b, KEY_1 },
49 { 0x001d, KEY_AUDIO }, /* DUAL SOUND */
50 { 0x001e, KEY_PLAY }, /* PLAY */
51 { 0x001f, KEY_CAMERA }, /* SNAPSHOT */
52 { 0x0040, KEY_VOLUMEUP }, /* Vol Up */
53 { 0x0048, KEY_7 },
54 { 0x004c, KEY_6 },
55 { 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */
56 { 0x0054, KEY_0 },
57};
58
59static struct rc_map_list digittrade_map = {
60 .map = {
61 .scan = digittrade,
62 .size = ARRAY_SIZE(digittrade),
63 .rc_type = RC_TYPE_NEC,
64 .name = RC_MAP_DIGITTRADE,
65 }
66};
67
68static int __init init_rc_map_digittrade(void)
69{
70 return rc_map_register(&digittrade_map);
71}
72
73static void __exit exit_rc_map_digittrade(void)
74{
75 rc_map_unregister(&digittrade_map);
76}
77
78module_init(init_rc_map_digittrade)
79module_exit(exit_rc_map_digittrade)
80
81MODULE_LICENSE("GPL");
82MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c
new file mode 100644
index 000000000000..d024fbf88bc4
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c
@@ -0,0 +1,76 @@
1/* dm1105-nec.h - Keytable for dm1105_nec Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* DVBWorld remotes
16 Igor M. Liplianin <liplianin@me.by>
17 */
18
19static struct rc_map_table dm1105_nec[] = {
20 { 0x0a, KEY_POWER2}, /* power */
21 { 0x0c, KEY_MUTE}, /* mute */
22 { 0x11, KEY_1},
23 { 0x12, KEY_2},
24 { 0x13, KEY_3},
25 { 0x14, KEY_4},
26 { 0x15, KEY_5},
27 { 0x16, KEY_6},
28 { 0x17, KEY_7},
29 { 0x18, KEY_8},
30 { 0x19, KEY_9},
31 { 0x10, KEY_0},
32 { 0x1c, KEY_CHANNELUP}, /* ch+ */
33 { 0x0f, KEY_CHANNELDOWN}, /* ch- */
34 { 0x1a, KEY_VOLUMEUP}, /* vol+ */
35 { 0x0e, KEY_VOLUMEDOWN}, /* vol- */
36 { 0x04, KEY_RECORD}, /* rec */
37 { 0x09, KEY_CHANNEL}, /* fav */
38 { 0x08, KEY_BACKSPACE}, /* rewind */
39 { 0x07, KEY_FASTFORWARD}, /* fast */
40 { 0x0b, KEY_PAUSE}, /* pause */
41 { 0x02, KEY_ESC}, /* cancel */
42 { 0x03, KEY_TAB}, /* tab */
43 { 0x00, KEY_UP}, /* up */
44 { 0x1f, KEY_ENTER}, /* ok */
45 { 0x01, KEY_DOWN}, /* down */
46 { 0x05, KEY_RECORD}, /* cap */
47 { 0x06, KEY_STOP}, /* stop */
48 { 0x40, KEY_ZOOM}, /* full */
49 { 0x1e, KEY_TV}, /* tvmode */
50 { 0x1b, KEY_B}, /* recall */
51};
52
53static struct rc_map_list dm1105_nec_map = {
54 .map = {
55 .scan = dm1105_nec,
56 .size = ARRAY_SIZE(dm1105_nec),
57 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
58 .name = RC_MAP_DM1105_NEC,
59 }
60};
61
62static int __init init_rc_map_dm1105_nec(void)
63{
64 return rc_map_register(&dm1105_nec_map);
65}
66
67static void __exit exit_rc_map_dm1105_nec(void)
68{
69 rc_map_unregister(&dm1105_nec_map);
70}
71
72module_init(init_rc_map_dm1105_nec)
73module_exit(exit_rc_map_dm1105_nec)
74
75MODULE_LICENSE("GPL");
76MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
new file mode 100644
index 000000000000..43912bd02a9e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
@@ -0,0 +1,78 @@
1/* dntv-live-dvb-t.h - Keytable for dntv_live_dvb_t Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* DigitalNow DNTV Live DVB-T Remote */
16
17static struct rc_map_table dntv_live_dvb_t[] = {
18 { 0x00, KEY_ESC }, /* 'go up a level?' */
19 /* Keys 0 to 9 */
20 { 0x0a, KEY_0 },
21 { 0x01, KEY_1 },
22 { 0x02, KEY_2 },
23 { 0x03, KEY_3 },
24 { 0x04, KEY_4 },
25 { 0x05, KEY_5 },
26 { 0x06, KEY_6 },
27 { 0x07, KEY_7 },
28 { 0x08, KEY_8 },
29 { 0x09, KEY_9 },
30
31 { 0x0b, KEY_TUNER }, /* tv/fm */
32 { 0x0c, KEY_SEARCH }, /* scan */
33 { 0x0d, KEY_STOP },
34 { 0x0e, KEY_PAUSE },
35 { 0x0f, KEY_LIST }, /* source */
36
37 { 0x10, KEY_MUTE },
38 { 0x11, KEY_REWIND }, /* backward << */
39 { 0x12, KEY_POWER },
40 { 0x13, KEY_CAMERA }, /* snap */
41 { 0x14, KEY_AUDIO }, /* stereo */
42 { 0x15, KEY_CLEAR }, /* reset */
43 { 0x16, KEY_PLAY },
44 { 0x17, KEY_ENTER },
45 { 0x18, KEY_ZOOM }, /* full screen */
46 { 0x19, KEY_FASTFORWARD }, /* forward >> */
47 { 0x1a, KEY_CHANNELUP },
48 { 0x1b, KEY_VOLUMEUP },
49 { 0x1c, KEY_INFO }, /* preview */
50 { 0x1d, KEY_RECORD }, /* record */
51 { 0x1e, KEY_CHANNELDOWN },
52 { 0x1f, KEY_VOLUMEDOWN },
53};
54
55static struct rc_map_list dntv_live_dvb_t_map = {
56 .map = {
57 .scan = dntv_live_dvb_t,
58 .size = ARRAY_SIZE(dntv_live_dvb_t),
59 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
60 .name = RC_MAP_DNTV_LIVE_DVB_T,
61 }
62};
63
64static int __init init_rc_map_dntv_live_dvb_t(void)
65{
66 return rc_map_register(&dntv_live_dvb_t_map);
67}
68
69static void __exit exit_rc_map_dntv_live_dvb_t(void)
70{
71 rc_map_unregister(&dntv_live_dvb_t_map);
72}
73
74module_init(init_rc_map_dntv_live_dvb_t)
75module_exit(exit_rc_map_dntv_live_dvb_t)
76
77MODULE_LICENSE("GPL");
78MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
new file mode 100644
index 000000000000..015e99de06de
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
@@ -0,0 +1,97 @@
1/* dntv-live-dvbt-pro.h - Keytable for dntv_live_dvbt_pro Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* DigitalNow DNTV Live! DVB-T Pro Remote */
16
17static struct rc_map_table dntv_live_dvbt_pro[] = {
18 { 0x16, KEY_POWER },
19 { 0x5b, KEY_HOME },
20
21 { 0x55, KEY_TV }, /* live tv */
22 { 0x58, KEY_TUNER }, /* digital Radio */
23 { 0x5a, KEY_RADIO }, /* FM radio */
24 { 0x59, KEY_DVD }, /* dvd menu */
25 { 0x03, KEY_1 },
26 { 0x01, KEY_2 },
27 { 0x06, KEY_3 },
28 { 0x09, KEY_4 },
29 { 0x1d, KEY_5 },
30 { 0x1f, KEY_6 },
31 { 0x0d, KEY_7 },
32 { 0x19, KEY_8 },
33 { 0x1b, KEY_9 },
34 { 0x0c, KEY_CANCEL },
35 { 0x15, KEY_0 },
36 { 0x4a, KEY_CLEAR },
37 { 0x13, KEY_BACK },
38 { 0x00, KEY_TAB },
39 { 0x4b, KEY_UP },
40 { 0x4e, KEY_LEFT },
41 { 0x4f, KEY_OK },
42 { 0x52, KEY_RIGHT },
43 { 0x51, KEY_DOWN },
44 { 0x1e, KEY_VOLUMEUP },
45 { 0x0a, KEY_VOLUMEDOWN },
46 { 0x02, KEY_CHANNELDOWN },
47 { 0x05, KEY_CHANNELUP },
48 { 0x11, KEY_RECORD },
49 { 0x14, KEY_PLAY },
50 { 0x4c, KEY_PAUSE },
51 { 0x1a, KEY_STOP },
52 { 0x40, KEY_REWIND },
53 { 0x12, KEY_FASTFORWARD },
54 { 0x41, KEY_PREVIOUSSONG }, /* replay |< */
55 { 0x42, KEY_NEXTSONG }, /* skip >| */
56 { 0x54, KEY_CAMERA }, /* capture */
57 { 0x50, KEY_LANGUAGE }, /* sap */
58 { 0x47, KEY_TV2 }, /* pip */
59 { 0x4d, KEY_SCREEN },
60 { 0x43, KEY_SUBTITLE },
61 { 0x10, KEY_MUTE },
62 { 0x49, KEY_AUDIO }, /* l/r */
63 { 0x07, KEY_SLEEP },
64 { 0x08, KEY_VIDEO }, /* a/v */
65 { 0x0e, KEY_PREVIOUS }, /* recall */
66 { 0x45, KEY_ZOOM }, /* zoom + */
67 { 0x46, KEY_ANGLE }, /* zoom - */
68 { 0x56, KEY_RED },
69 { 0x57, KEY_GREEN },
70 { 0x5c, KEY_YELLOW },
71 { 0x5d, KEY_BLUE },
72};
73
74static struct rc_map_list dntv_live_dvbt_pro_map = {
75 .map = {
76 .scan = dntv_live_dvbt_pro,
77 .size = ARRAY_SIZE(dntv_live_dvbt_pro),
78 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
79 .name = RC_MAP_DNTV_LIVE_DVBT_PRO,
80 }
81};
82
83static int __init init_rc_map_dntv_live_dvbt_pro(void)
84{
85 return rc_map_register(&dntv_live_dvbt_pro_map);
86}
87
88static void __exit exit_rc_map_dntv_live_dvbt_pro(void)
89{
90 rc_map_unregister(&dntv_live_dvbt_pro_map);
91}
92
93module_init(init_rc_map_dntv_live_dvbt_pro)
94module_exit(exit_rc_map_dntv_live_dvbt_pro)
95
96MODULE_LICENSE("GPL");
97MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c
new file mode 100644
index 000000000000..269d4299da34
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-em-terratec.c
@@ -0,0 +1,69 @@
1/* em-terratec.h - Keytable for em_terratec Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table em_terratec[] = {
16 { 0x01, KEY_CHANNEL },
17 { 0x02, KEY_SELECT },
18 { 0x03, KEY_MUTE },
19 { 0x04, KEY_POWER },
20 { 0x05, KEY_1 },
21 { 0x06, KEY_2 },
22 { 0x07, KEY_3 },
23 { 0x08, KEY_CHANNELUP },
24 { 0x09, KEY_4 },
25 { 0x0a, KEY_5 },
26 { 0x0b, KEY_6 },
27 { 0x0c, KEY_CHANNELDOWN },
28 { 0x0d, KEY_7 },
29 { 0x0e, KEY_8 },
30 { 0x0f, KEY_9 },
31 { 0x10, KEY_VOLUMEUP },
32 { 0x11, KEY_0 },
33 { 0x12, KEY_MENU },
34 { 0x13, KEY_PRINT },
35 { 0x14, KEY_VOLUMEDOWN },
36 { 0x16, KEY_PAUSE },
37 { 0x18, KEY_RECORD },
38 { 0x19, KEY_REWIND },
39 { 0x1a, KEY_PLAY },
40 { 0x1b, KEY_FORWARD },
41 { 0x1c, KEY_BACKSPACE },
42 { 0x1e, KEY_STOP },
43 { 0x40, KEY_ZOOM },
44};
45
46static struct rc_map_list em_terratec_map = {
47 .map = {
48 .scan = em_terratec,
49 .size = ARRAY_SIZE(em_terratec),
50 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
51 .name = RC_MAP_EM_TERRATEC,
52 }
53};
54
55static int __init init_rc_map_em_terratec(void)
56{
57 return rc_map_register(&em_terratec_map);
58}
59
60static void __exit exit_rc_map_em_terratec(void)
61{
62 rc_map_unregister(&em_terratec_map);
63}
64
65module_init(init_rc_map_em_terratec)
66module_exit(exit_rc_map_em_terratec)
67
68MODULE_LICENSE("GPL");
69MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
new file mode 100644
index 000000000000..e388698a0697
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
@@ -0,0 +1,81 @@
1/* encore-enltv-fm53.h - Keytable for encore_enltv_fm53 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Encore ENLTV-FM v5.3
16 Mauro Carvalho Chehab <mchehab@infradead.org>
17 */
18
19static struct rc_map_table encore_enltv_fm53[] = {
20 { 0x10, KEY_POWER2},
21 { 0x06, KEY_MUTE},
22
23 { 0x09, KEY_1},
24 { 0x1d, KEY_2},
25 { 0x1f, KEY_3},
26 { 0x19, KEY_4},
27 { 0x1b, KEY_5},
28 { 0x11, KEY_6},
29 { 0x17, KEY_7},
30 { 0x12, KEY_8},
31 { 0x16, KEY_9},
32 { 0x48, KEY_0},
33
34 { 0x04, KEY_LIST}, /* -/-- */
35 { 0x40, KEY_LAST}, /* recall */
36
37 { 0x02, KEY_MODE}, /* TV/AV */
38 { 0x05, KEY_CAMERA}, /* SNAPSHOT */
39
40 { 0x4c, KEY_CHANNELUP}, /* UP */
41 { 0x00, KEY_CHANNELDOWN}, /* DOWN */
42 { 0x0d, KEY_VOLUMEUP}, /* RIGHT */
43 { 0x15, KEY_VOLUMEDOWN}, /* LEFT */
44 { 0x49, KEY_ENTER}, /* OK */
45
46 { 0x54, KEY_RECORD},
47 { 0x4d, KEY_PLAY}, /* pause */
48
49 { 0x1e, KEY_MENU}, /* video setting */
50 { 0x0e, KEY_RIGHT}, /* <- */
51 { 0x1a, KEY_LEFT}, /* -> */
52
53 { 0x0a, KEY_CLEAR}, /* video default */
54 { 0x0c, KEY_ZOOM}, /* hide pannel */
55 { 0x47, KEY_SLEEP}, /* shutdown */
56};
57
58static struct rc_map_list encore_enltv_fm53_map = {
59 .map = {
60 .scan = encore_enltv_fm53,
61 .size = ARRAY_SIZE(encore_enltv_fm53),
62 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
63 .name = RC_MAP_ENCORE_ENLTV_FM53,
64 }
65};
66
67static int __init init_rc_map_encore_enltv_fm53(void)
68{
69 return rc_map_register(&encore_enltv_fm53_map);
70}
71
72static void __exit exit_rc_map_encore_enltv_fm53(void)
73{
74 rc_map_unregister(&encore_enltv_fm53_map);
75}
76
77module_init(init_rc_map_encore_enltv_fm53)
78module_exit(exit_rc_map_encore_enltv_fm53)
79
80MODULE_LICENSE("GPL");
81MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c
new file mode 100644
index 000000000000..afa4e92284ef
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-encore-enltv.c
@@ -0,0 +1,112 @@
1/* encore-enltv.h - Keytable for encore_enltv Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons
16 Juan Pablo Sormani <sorman@gmail.com> */
17
18static struct rc_map_table encore_enltv[] = {
19
20 /* Power button does nothing, neither in Windows app,
21 although it sends data (used for BIOS wakeup?) */
22 { 0x0d, KEY_MUTE },
23
24 { 0x1e, KEY_TV },
25 { 0x00, KEY_VIDEO },
26 { 0x01, KEY_AUDIO }, /* music */
27 { 0x02, KEY_MHP }, /* picture */
28
29 { 0x1f, KEY_1 },
30 { 0x03, KEY_2 },
31 { 0x04, KEY_3 },
32 { 0x05, KEY_4 },
33 { 0x1c, KEY_5 },
34 { 0x06, KEY_6 },
35 { 0x07, KEY_7 },
36 { 0x08, KEY_8 },
37 { 0x1d, KEY_9 },
38 { 0x0a, KEY_0 },
39
40 { 0x09, KEY_LIST }, /* -/-- */
41 { 0x0b, KEY_LAST }, /* recall */
42
43 { 0x14, KEY_HOME }, /* win start menu */
44 { 0x15, KEY_EXIT }, /* exit */
45 { 0x16, KEY_CHANNELUP }, /* UP */
46 { 0x12, KEY_CHANNELDOWN }, /* DOWN */
47 { 0x0c, KEY_VOLUMEUP }, /* RIGHT */
48 { 0x17, KEY_VOLUMEDOWN }, /* LEFT */
49
50 { 0x18, KEY_ENTER }, /* OK */
51
52 { 0x0e, KEY_ESC },
53 { 0x13, KEY_CYCLEWINDOWS }, /* desktop */
54 { 0x11, KEY_TAB },
55 { 0x19, KEY_SWITCHVIDEOMODE }, /* switch */
56
57 { 0x1a, KEY_MENU },
58 { 0x1b, KEY_ZOOM }, /* fullscreen */
59 { 0x44, KEY_TIME }, /* time shift */
60 { 0x40, KEY_MODE }, /* source */
61
62 { 0x5a, KEY_RECORD },
63 { 0x42, KEY_PLAY }, /* play/pause */
64 { 0x45, KEY_STOP },
65 { 0x43, KEY_CAMERA }, /* camera icon */
66
67 { 0x48, KEY_REWIND },
68 { 0x4a, KEY_FASTFORWARD },
69 { 0x49, KEY_PREVIOUS },
70 { 0x4b, KEY_NEXT },
71
72 { 0x4c, KEY_FAVORITES }, /* tv wall */
73 { 0x4d, KEY_SOUND }, /* DVD sound */
74 { 0x4e, KEY_LANGUAGE }, /* DVD lang */
75 { 0x4f, KEY_TEXT }, /* DVD text */
76
77 { 0x50, KEY_SLEEP }, /* shutdown */
78 { 0x51, KEY_MODE }, /* stereo > main */
79 { 0x52, KEY_SELECT }, /* stereo > sap */
80 { 0x53, KEY_PROG1 }, /* teletext */
81
82
83 { 0x59, KEY_RED }, /* AP1 */
84 { 0x41, KEY_GREEN }, /* AP2 */
85 { 0x47, KEY_YELLOW }, /* AP3 */
86 { 0x57, KEY_BLUE }, /* AP4 */
87};
88
89static struct rc_map_list encore_enltv_map = {
90 .map = {
91 .scan = encore_enltv,
92 .size = ARRAY_SIZE(encore_enltv),
93 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
94 .name = RC_MAP_ENCORE_ENLTV,
95 }
96};
97
98static int __init init_rc_map_encore_enltv(void)
99{
100 return rc_map_register(&encore_enltv_map);
101}
102
103static void __exit exit_rc_map_encore_enltv(void)
104{
105 rc_map_unregister(&encore_enltv_map);
106}
107
108module_init(init_rc_map_encore_enltv)
109module_exit(exit_rc_map_encore_enltv)
110
111MODULE_LICENSE("GPL");
112MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c
new file mode 100644
index 000000000000..7d5b00ed4ff2
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c
@@ -0,0 +1,90 @@
1/* encore-enltv2.h - Keytable for encore_enltv2 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton
16 Mauro Carvalho Chehab <mchehab@infradead.org> */
17
18static struct rc_map_table encore_enltv2[] = {
19 { 0x4c, KEY_POWER2 },
20 { 0x4a, KEY_TUNER },
21 { 0x40, KEY_1 },
22 { 0x60, KEY_2 },
23 { 0x50, KEY_3 },
24 { 0x70, KEY_4 },
25 { 0x48, KEY_5 },
26 { 0x68, KEY_6 },
27 { 0x58, KEY_7 },
28 { 0x78, KEY_8 },
29 { 0x44, KEY_9 },
30 { 0x54, KEY_0 },
31
32 { 0x64, KEY_LAST }, /* +100 */
33 { 0x4e, KEY_AGAIN }, /* Recall */
34
35 { 0x6c, KEY_SWITCHVIDEOMODE }, /* Video Source */
36 { 0x5e, KEY_MENU },
37 { 0x56, KEY_SCREEN },
38 { 0x7a, KEY_SETUP },
39
40 { 0x46, KEY_MUTE },
41 { 0x5c, KEY_MODE }, /* Stereo */
42 { 0x74, KEY_INFO },
43 { 0x7c, KEY_CLEAR },
44
45 { 0x55, KEY_UP },
46 { 0x49, KEY_DOWN },
47 { 0x7e, KEY_LEFT },
48 { 0x59, KEY_RIGHT },
49 { 0x6a, KEY_ENTER },
50
51 { 0x42, KEY_VOLUMEUP },
52 { 0x62, KEY_VOLUMEDOWN },
53 { 0x52, KEY_CHANNELUP },
54 { 0x72, KEY_CHANNELDOWN },
55
56 { 0x41, KEY_RECORD },
57 { 0x51, KEY_CAMERA }, /* Snapshot */
58 { 0x75, KEY_TIME }, /* Timeshift */
59 { 0x71, KEY_TV2 }, /* PIP */
60
61 { 0x45, KEY_REWIND },
62 { 0x6f, KEY_PAUSE },
63 { 0x7d, KEY_FORWARD },
64 { 0x79, KEY_STOP },
65};
66
67static struct rc_map_list encore_enltv2_map = {
68 .map = {
69 .scan = encore_enltv2,
70 .size = ARRAY_SIZE(encore_enltv2),
71 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
72 .name = RC_MAP_ENCORE_ENLTV2,
73 }
74};
75
76static int __init init_rc_map_encore_enltv2(void)
77{
78 return rc_map_register(&encore_enltv2_map);
79}
80
81static void __exit exit_rc_map_encore_enltv2(void)
82{
83 rc_map_unregister(&encore_enltv2_map);
84}
85
86module_init(init_rc_map_encore_enltv2)
87module_exit(exit_rc_map_encore_enltv2)
88
89MODULE_LICENSE("GPL");
90MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c
new file mode 100644
index 000000000000..a2bf24f6dfbb
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-evga-indtube.c
@@ -0,0 +1,61 @@
1/* evga-indtube.h - Keytable for evga_indtube Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* EVGA inDtube
16 Devin Heitmueller <devin.heitmueller@gmail.com>
17 */
18
19static struct rc_map_table evga_indtube[] = {
20 { 0x12, KEY_POWER},
21 { 0x02, KEY_MODE}, /* TV */
22 { 0x14, KEY_MUTE},
23 { 0x1a, KEY_CHANNELUP},
24 { 0x16, KEY_TV2}, /* PIP */
25 { 0x1d, KEY_VOLUMEUP},
26 { 0x05, KEY_CHANNELDOWN},
27 { 0x0f, KEY_PLAYPAUSE},
28 { 0x19, KEY_VOLUMEDOWN},
29 { 0x1c, KEY_REWIND},
30 { 0x0d, KEY_RECORD},
31 { 0x18, KEY_FORWARD},
32 { 0x1e, KEY_PREVIOUS},
33 { 0x1b, KEY_STOP},
34 { 0x1f, KEY_NEXT},
35 { 0x13, KEY_CAMERA},
36};
37
38static struct rc_map_list evga_indtube_map = {
39 .map = {
40 .scan = evga_indtube,
41 .size = ARRAY_SIZE(evga_indtube),
42 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
43 .name = RC_MAP_EVGA_INDTUBE,
44 }
45};
46
47static int __init init_rc_map_evga_indtube(void)
48{
49 return rc_map_register(&evga_indtube_map);
50}
51
52static void __exit exit_rc_map_evga_indtube(void)
53{
54 rc_map_unregister(&evga_indtube_map);
55}
56
57module_init(init_rc_map_evga_indtube)
58module_exit(exit_rc_map_evga_indtube)
59
60MODULE_LICENSE("GPL");
61MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c
new file mode 100644
index 000000000000..1e8e5b2d6e36
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-eztv.c
@@ -0,0 +1,96 @@
1/* eztv.h - Keytable for eztv Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Alfons Geser <a.geser@cox.net>
16 * updates from Job D. R. Borges <jobdrb@ig.com.br> */
17
18static struct rc_map_table eztv[] = {
19 { 0x12, KEY_POWER },
20 { 0x01, KEY_TV }, /* DVR */
21 { 0x15, KEY_DVD }, /* DVD */
22 { 0x17, KEY_AUDIO }, /* music */
23 /* DVR mode / DVD mode / music mode */
24
25 { 0x1b, KEY_MUTE }, /* mute */
26 { 0x02, KEY_LANGUAGE }, /* MTS/SAP / audio / autoseek */
27 { 0x1e, KEY_SUBTITLE }, /* closed captioning / subtitle / seek */
28 { 0x16, KEY_ZOOM }, /* full screen */
29 { 0x1c, KEY_VIDEO }, /* video source / eject / delall */
30 { 0x1d, KEY_RESTART }, /* playback / angle / del */
31 { 0x2f, KEY_SEARCH }, /* scan / menu / playlist */
32 { 0x30, KEY_CHANNEL }, /* CH surfing / bookmark / memo */
33
34 { 0x31, KEY_HELP }, /* help */
35 { 0x32, KEY_MODE }, /* num/memo */
36 { 0x33, KEY_ESC }, /* cancel */
37
38 { 0x0c, KEY_UP }, /* up */
39 { 0x10, KEY_DOWN }, /* down */
40 { 0x08, KEY_LEFT }, /* left */
41 { 0x04, KEY_RIGHT }, /* right */
42 { 0x03, KEY_SELECT }, /* select */
43
44 { 0x1f, KEY_REWIND }, /* rewind */
45 { 0x20, KEY_PLAYPAUSE },/* play/pause */
46 { 0x29, KEY_FORWARD }, /* forward */
47 { 0x14, KEY_AGAIN }, /* repeat */
48 { 0x2b, KEY_RECORD }, /* recording */
49 { 0x2c, KEY_STOP }, /* stop */
50 { 0x2d, KEY_PLAY }, /* play */
51 { 0x2e, KEY_CAMERA }, /* snapshot / shuffle */
52
53 { 0x00, KEY_0 },
54 { 0x05, KEY_1 },
55 { 0x06, KEY_2 },
56 { 0x07, KEY_3 },
57 { 0x09, KEY_4 },
58 { 0x0a, KEY_5 },
59 { 0x0b, KEY_6 },
60 { 0x0d, KEY_7 },
61 { 0x0e, KEY_8 },
62 { 0x0f, KEY_9 },
63
64 { 0x2a, KEY_VOLUMEUP },
65 { 0x11, KEY_VOLUMEDOWN },
66 { 0x18, KEY_CHANNELUP },/* CH.tracking up */
67 { 0x19, KEY_CHANNELDOWN },/* CH.tracking down */
68
69 { 0x13, KEY_ENTER }, /* enter */
70 { 0x21, KEY_DOT }, /* . (decimal dot) */
71};
72
73static struct rc_map_list eztv_map = {
74 .map = {
75 .scan = eztv,
76 .size = ARRAY_SIZE(eztv),
77 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
78 .name = RC_MAP_EZTV,
79 }
80};
81
82static int __init init_rc_map_eztv(void)
83{
84 return rc_map_register(&eztv_map);
85}
86
87static void __exit exit_rc_map_eztv(void)
88{
89 rc_map_unregister(&eztv_map);
90}
91
92module_init(init_rc_map_eztv)
93module_exit(exit_rc_map_eztv)
94
95MODULE_LICENSE("GPL");
96MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c
new file mode 100644
index 000000000000..aea2f4acf7d8
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-flydvb.c
@@ -0,0 +1,77 @@
1/* flydvb.h - Keytable for flydvb Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table flydvb[] = {
16 { 0x01, KEY_ZOOM }, /* Full Screen */
17 { 0x00, KEY_POWER }, /* Power */
18
19 { 0x03, KEY_1 },
20 { 0x04, KEY_2 },
21 { 0x05, KEY_3 },
22 { 0x07, KEY_4 },
23 { 0x08, KEY_5 },
24 { 0x09, KEY_6 },
25 { 0x0b, KEY_7 },
26 { 0x0c, KEY_8 },
27 { 0x0d, KEY_9 },
28 { 0x06, KEY_AGAIN }, /* Recall */
29 { 0x0f, KEY_0 },
30 { 0x10, KEY_MUTE }, /* Mute */
31 { 0x02, KEY_RADIO }, /* TV/Radio */
32 { 0x1b, KEY_LANGUAGE }, /* SAP (Second Audio Program) */
33
34 { 0x14, KEY_VOLUMEUP }, /* VOL+ */
35 { 0x17, KEY_VOLUMEDOWN }, /* VOL- */
36 { 0x12, KEY_CHANNELUP }, /* CH+ */
37 { 0x13, KEY_CHANNELDOWN }, /* CH- */
38 { 0x1d, KEY_ENTER }, /* Enter */
39
40 { 0x1a, KEY_MODE }, /* PIP */
41 { 0x18, KEY_TUNER }, /* Source */
42
43 { 0x1e, KEY_RECORD }, /* Record/Pause */
44 { 0x15, KEY_ANGLE }, /* Swap (no label on key) */
45 { 0x1c, KEY_PAUSE }, /* Timeshift/Pause */
46 { 0x19, KEY_BACK }, /* Rewind << */
47 { 0x0a, KEY_PLAYPAUSE }, /* Play/Pause */
48 { 0x1f, KEY_FORWARD }, /* Forward >> */
49 { 0x16, KEY_PREVIOUS }, /* Back |<< */
50 { 0x11, KEY_STOP }, /* Stop */
51 { 0x0e, KEY_NEXT }, /* End >>| */
52};
53
54static struct rc_map_list flydvb_map = {
55 .map = {
56 .scan = flydvb,
57 .size = ARRAY_SIZE(flydvb),
58 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
59 .name = RC_MAP_FLYDVB,
60 }
61};
62
63static int __init init_rc_map_flydvb(void)
64{
65 return rc_map_register(&flydvb_map);
66}
67
68static void __exit exit_rc_map_flydvb(void)
69{
70 rc_map_unregister(&flydvb_map);
71}
72
73module_init(init_rc_map_flydvb)
74module_exit(exit_rc_map_flydvb)
75
76MODULE_LICENSE("GPL");
77MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c
new file mode 100644
index 000000000000..5bbe68371756
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-flyvideo.c
@@ -0,0 +1,70 @@
1/* flyvideo.h - Keytable for flyvideo Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table flyvideo[] = {
16 { 0x0f, KEY_0 },
17 { 0x03, KEY_1 },
18 { 0x04, KEY_2 },
19 { 0x05, KEY_3 },
20 { 0x07, KEY_4 },
21 { 0x08, KEY_5 },
22 { 0x09, KEY_6 },
23 { 0x0b, KEY_7 },
24 { 0x0c, KEY_8 },
25 { 0x0d, KEY_9 },
26
27 { 0x0e, KEY_MODE }, /* Air/Cable */
28 { 0x11, KEY_VIDEO }, /* Video */
29 { 0x15, KEY_AUDIO }, /* Audio */
30 { 0x00, KEY_POWER }, /* Power */
31 { 0x18, KEY_TUNER }, /* AV Source */
32 { 0x02, KEY_ZOOM }, /* Fullscreen */
33 { 0x1a, KEY_LANGUAGE }, /* Stereo */
34 { 0x1b, KEY_MUTE }, /* Mute */
35 { 0x14, KEY_VOLUMEUP }, /* Volume + */
36 { 0x17, KEY_VOLUMEDOWN },/* Volume - */
37 { 0x12, KEY_CHANNELUP },/* Channel + */
38 { 0x13, KEY_CHANNELDOWN },/* Channel - */
39 { 0x06, KEY_AGAIN }, /* Recall */
40 { 0x10, KEY_ENTER }, /* Enter */
41
42 { 0x19, KEY_BACK }, /* Rewind ( <<< ) */
43 { 0x1f, KEY_FORWARD }, /* Forward ( >>> ) */
44 { 0x0a, KEY_ANGLE }, /* no label, may be used as the PAUSE button */
45};
46
47static struct rc_map_list flyvideo_map = {
48 .map = {
49 .scan = flyvideo,
50 .size = ARRAY_SIZE(flyvideo),
51 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
52 .name = RC_MAP_FLYVIDEO,
53 }
54};
55
56static int __init init_rc_map_flyvideo(void)
57{
58 return rc_map_register(&flyvideo_map);
59}
60
61static void __exit exit_rc_map_flyvideo(void)
62{
63 rc_map_unregister(&flyvideo_map);
64}
65
66module_init(init_rc_map_flyvideo)
67module_exit(exit_rc_map_flyvideo)
68
69MODULE_LICENSE("GPL");
70MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
new file mode 100644
index 000000000000..c80b25c65b57
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
@@ -0,0 +1,98 @@
1/* fusionhdtv-mce.h - Keytable for fusionhdtv_mce Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* DViCO FUSION HDTV MCE remote */
16
17static struct rc_map_table fusionhdtv_mce[] = {
18
19 { 0x0b, KEY_1 },
20 { 0x17, KEY_2 },
21 { 0x1b, KEY_3 },
22 { 0x07, KEY_4 },
23 { 0x50, KEY_5 },
24 { 0x54, KEY_6 },
25 { 0x48, KEY_7 },
26 { 0x4c, KEY_8 },
27 { 0x58, KEY_9 },
28 { 0x03, KEY_0 },
29
30 { 0x5e, KEY_OK },
31 { 0x51, KEY_UP },
32 { 0x53, KEY_DOWN },
33 { 0x5b, KEY_LEFT },
34 { 0x5f, KEY_RIGHT },
35
36 { 0x02, KEY_TV }, /* Labeled DTV on remote */
37 { 0x0e, KEY_MP3 },
38 { 0x1a, KEY_DVD },
39 { 0x1e, KEY_FAVORITES }, /* Labeled CPF on remote */
40 { 0x16, KEY_SETUP },
41 { 0x46, KEY_POWER2 }, /* TV On/Off button on remote */
42 { 0x0a, KEY_EPG }, /* Labeled Guide on remote */
43
44 { 0x49, KEY_BACK },
45 { 0x59, KEY_INFO }, /* Labeled MORE on remote */
46 { 0x4d, KEY_MENU }, /* Labeled DVDMENU on remote */
47 { 0x55, KEY_CYCLEWINDOWS }, /* Labeled ALT-TAB on remote */
48
49 { 0x0f, KEY_PREVIOUSSONG }, /* Labeled |<< REPLAY on remote */
50 { 0x12, KEY_NEXTSONG }, /* Labeled >>| SKIP on remote */
51 { 0x42, KEY_ENTER }, /* Labeled START with a green
52 MS windows logo on remote */
53
54 { 0x15, KEY_VOLUMEUP },
55 { 0x05, KEY_VOLUMEDOWN },
56 { 0x11, KEY_CHANNELUP },
57 { 0x09, KEY_CHANNELDOWN },
58
59 { 0x52, KEY_CAMERA },
60 { 0x5a, KEY_TUNER },
61 { 0x19, KEY_OPEN },
62
63 { 0x13, KEY_MODE }, /* 4:3 16:9 select */
64 { 0x1f, KEY_ZOOM },
65
66 { 0x43, KEY_REWIND },
67 { 0x47, KEY_PLAYPAUSE },
68 { 0x4f, KEY_FASTFORWARD },
69 { 0x57, KEY_MUTE },
70 { 0x0d, KEY_STOP },
71 { 0x01, KEY_RECORD },
72 { 0x4e, KEY_POWER },
73};
74
75static struct rc_map_list fusionhdtv_mce_map = {
76 .map = {
77 .scan = fusionhdtv_mce,
78 .size = ARRAY_SIZE(fusionhdtv_mce),
79 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
80 .name = RC_MAP_FUSIONHDTV_MCE,
81 }
82};
83
84static int __init init_rc_map_fusionhdtv_mce(void)
85{
86 return rc_map_register(&fusionhdtv_mce_map);
87}
88
89static void __exit exit_rc_map_fusionhdtv_mce(void)
90{
91 rc_map_unregister(&fusionhdtv_mce_map);
92}
93
94module_init(init_rc_map_fusionhdtv_mce)
95module_exit(exit_rc_map_fusionhdtv_mce)
96
97MODULE_LICENSE("GPL");
98MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
new file mode 100644
index 000000000000..068c9ead98dd
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
@@ -0,0 +1,81 @@
1/* gadmei-rm008z.h - Keytable for gadmei_rm008z Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* GADMEI UTV330+ RM008Z remote
16 Shine Liu <shinel@foxmail.com>
17 */
18
19static struct rc_map_table gadmei_rm008z[] = {
20 { 0x14, KEY_POWER2}, /* POWER OFF */
21 { 0x0c, KEY_MUTE}, /* MUTE */
22
23 { 0x18, KEY_TV}, /* TV */
24 { 0x0e, KEY_VIDEO}, /* AV */
25 { 0x0b, KEY_AUDIO}, /* SV */
26 { 0x0f, KEY_RADIO}, /* FM */
27
28 { 0x00, KEY_1},
29 { 0x01, KEY_2},
30 { 0x02, KEY_3},
31 { 0x03, KEY_4},
32 { 0x04, KEY_5},
33 { 0x05, KEY_6},
34 { 0x06, KEY_7},
35 { 0x07, KEY_8},
36 { 0x08, KEY_9},
37 { 0x09, KEY_0},
38 { 0x0a, KEY_INFO}, /* OSD */
39 { 0x1c, KEY_BACKSPACE}, /* LAST */
40
41 { 0x0d, KEY_PLAY}, /* PLAY */
42 { 0x1e, KEY_CAMERA}, /* SNAPSHOT */
43 { 0x1a, KEY_RECORD}, /* RECORD */
44 { 0x17, KEY_STOP}, /* STOP */
45
46 { 0x1f, KEY_UP}, /* UP */
47 { 0x44, KEY_DOWN}, /* DOWN */
48 { 0x46, KEY_TAB}, /* BACK */
49 { 0x4a, KEY_ZOOM}, /* FULLSECREEN */
50
51 { 0x10, KEY_VOLUMEUP}, /* VOLUMEUP */
52 { 0x11, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */
53 { 0x12, KEY_CHANNELUP}, /* CHANNELUP */
54 { 0x13, KEY_CHANNELDOWN}, /* CHANNELDOWN */
55 { 0x15, KEY_ENTER}, /* OK */
56};
57
58static struct rc_map_list gadmei_rm008z_map = {
59 .map = {
60 .scan = gadmei_rm008z,
61 .size = ARRAY_SIZE(gadmei_rm008z),
62 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
63 .name = RC_MAP_GADMEI_RM008Z,
64 }
65};
66
67static int __init init_rc_map_gadmei_rm008z(void)
68{
69 return rc_map_register(&gadmei_rm008z_map);
70}
71
72static void __exit exit_rc_map_gadmei_rm008z(void)
73{
74 rc_map_unregister(&gadmei_rm008z_map);
75}
76
77module_init(init_rc_map_gadmei_rm008z)
78module_exit(exit_rc_map_gadmei_rm008z)
79
80MODULE_LICENSE("GPL");
81MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
new file mode 100644
index 000000000000..cdbbed467926
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
@@ -0,0 +1,84 @@
1/* genius-tvgo-a11mce.h - Keytable for genius_tvgo_a11mce Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 * Remote control for the Genius TVGO A11MCE
17 * Adrian Pardini <pardo.bsso@gmail.com>
18 */
19
20static struct rc_map_table genius_tvgo_a11mce[] = {
21 /* Keys 0 to 9 */
22 { 0x48, KEY_0 },
23 { 0x09, KEY_1 },
24 { 0x1d, KEY_2 },
25 { 0x1f, KEY_3 },
26 { 0x19, KEY_4 },
27 { 0x1b, KEY_5 },
28 { 0x11, KEY_6 },
29 { 0x17, KEY_7 },
30 { 0x12, KEY_8 },
31 { 0x16, KEY_9 },
32
33 { 0x54, KEY_RECORD }, /* recording */
34 { 0x06, KEY_MUTE }, /* mute */
35 { 0x10, KEY_POWER },
36 { 0x40, KEY_LAST }, /* recall */
37 { 0x4c, KEY_CHANNELUP }, /* channel / program + */
38 { 0x00, KEY_CHANNELDOWN }, /* channel / program - */
39 { 0x0d, KEY_VOLUMEUP },
40 { 0x15, KEY_VOLUMEDOWN },
41 { 0x4d, KEY_OK }, /* also labeled as Pause */
42 { 0x1c, KEY_ZOOM }, /* full screen and Stop*/
43 { 0x02, KEY_MODE }, /* AV Source or Rewind*/
44 { 0x04, KEY_LIST }, /* -/-- */
45 /* small arrows above numbers */
46 { 0x1a, KEY_NEXT }, /* also Fast Forward */
47 { 0x0e, KEY_PREVIOUS }, /* also Rewind */
48 /* these are in a rather non standard layout and have
49 an alternate name written */
50 { 0x1e, KEY_UP }, /* Video Setting */
51 { 0x0a, KEY_DOWN }, /* Video Default */
52 { 0x05, KEY_CAMERA }, /* Snapshot */
53 { 0x0c, KEY_RIGHT }, /* Hide Panel */
54 /* Four buttons without label */
55 { 0x49, KEY_RED },
56 { 0x0b, KEY_GREEN },
57 { 0x13, KEY_YELLOW },
58 { 0x50, KEY_BLUE },
59};
60
61static struct rc_map_list genius_tvgo_a11mce_map = {
62 .map = {
63 .scan = genius_tvgo_a11mce,
64 .size = ARRAY_SIZE(genius_tvgo_a11mce),
65 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
66 .name = RC_MAP_GENIUS_TVGO_A11MCE,
67 }
68};
69
70static int __init init_rc_map_genius_tvgo_a11mce(void)
71{
72 return rc_map_register(&genius_tvgo_a11mce_map);
73}
74
75static void __exit exit_rc_map_genius_tvgo_a11mce(void)
76{
77 rc_map_unregister(&genius_tvgo_a11mce_map);
78}
79
80module_init(init_rc_map_genius_tvgo_a11mce)
81module_exit(exit_rc_map_genius_tvgo_a11mce)
82
83MODULE_LICENSE("GPL");
84MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c
new file mode 100644
index 000000000000..a38bdde8c140
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-gotview7135.c
@@ -0,0 +1,79 @@
1/* gotview7135.h - Keytable for gotview7135 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Mike Baikov <mike@baikov.com> */
16
17static struct rc_map_table gotview7135[] = {
18
19 { 0x11, KEY_POWER },
20 { 0x35, KEY_TV },
21 { 0x1b, KEY_0 },
22 { 0x29, KEY_1 },
23 { 0x19, KEY_2 },
24 { 0x39, KEY_3 },
25 { 0x1f, KEY_4 },
26 { 0x2c, KEY_5 },
27 { 0x21, KEY_6 },
28 { 0x24, KEY_7 },
29 { 0x18, KEY_8 },
30 { 0x2b, KEY_9 },
31 { 0x3b, KEY_AGAIN }, /* LOOP */
32 { 0x06, KEY_AUDIO },
33 { 0x31, KEY_PRINT }, /* PREVIEW */
34 { 0x3e, KEY_VIDEO },
35 { 0x10, KEY_CHANNELUP },
36 { 0x20, KEY_CHANNELDOWN },
37 { 0x0c, KEY_VOLUMEDOWN },
38 { 0x28, KEY_VOLUMEUP },
39 { 0x08, KEY_MUTE },
40 { 0x26, KEY_SEARCH }, /* SCAN */
41 { 0x3f, KEY_CAMERA }, /* SNAPSHOT */
42 { 0x12, KEY_RECORD },
43 { 0x32, KEY_STOP },
44 { 0x3c, KEY_PLAY },
45 { 0x1d, KEY_REWIND },
46 { 0x2d, KEY_PAUSE },
47 { 0x0d, KEY_FORWARD },
48 { 0x05, KEY_ZOOM }, /*FULL*/
49
50 { 0x2a, KEY_F21 }, /* LIVE TIMESHIFT */
51 { 0x0e, KEY_F22 }, /* MIN TIMESHIFT */
52 { 0x1e, KEY_TIME }, /* TIMESHIFT */
53 { 0x38, KEY_F24 }, /* NORMAL TIMESHIFT */
54};
55
56static struct rc_map_list gotview7135_map = {
57 .map = {
58 .scan = gotview7135,
59 .size = ARRAY_SIZE(gotview7135),
60 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
61 .name = RC_MAP_GOTVIEW7135,
62 }
63};
64
65static int __init init_rc_map_gotview7135(void)
66{
67 return rc_map_register(&gotview7135_map);
68}
69
70static void __exit exit_rc_map_gotview7135(void)
71{
72 rc_map_unregister(&gotview7135_map);
73}
74
75module_init(init_rc_map_gotview7135)
76module_exit(exit_rc_map_gotview7135)
77
78MODULE_LICENSE("GPL");
79MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-hauppauge-new.c b/drivers/media/rc/keymaps/rc-hauppauge-new.c
new file mode 100644
index 000000000000..bd11da46e56a
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-hauppauge-new.c
@@ -0,0 +1,100 @@
1/* hauppauge-new.h - Keytable for hauppauge_new Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Hauppauge: the newer, gray remotes (seems there are multiple
16 * slightly different versions), shipped with cx88+ivtv cards.
17 * almost rc5 coding, but some non-standard keys */
18
19static struct rc_map_table hauppauge_new[] = {
20 /* Keys 0 to 9 */
21 { 0x00, KEY_0 },
22 { 0x01, KEY_1 },
23 { 0x02, KEY_2 },
24 { 0x03, KEY_3 },
25 { 0x04, KEY_4 },
26 { 0x05, KEY_5 },
27 { 0x06, KEY_6 },
28 { 0x07, KEY_7 },
29 { 0x08, KEY_8 },
30 { 0x09, KEY_9 },
31
32 { 0x0a, KEY_TEXT }, /* keypad asterisk as well */
33 { 0x0b, KEY_RED }, /* red button */
34 { 0x0c, KEY_RADIO },
35 { 0x0d, KEY_MENU },
36 { 0x0e, KEY_SUBTITLE }, /* also the # key */
37 { 0x0f, KEY_MUTE },
38 { 0x10, KEY_VOLUMEUP },
39 { 0x11, KEY_VOLUMEDOWN },
40 { 0x12, KEY_PREVIOUS }, /* previous channel */
41 { 0x14, KEY_UP },
42 { 0x15, KEY_DOWN },
43 { 0x16, KEY_LEFT },
44 { 0x17, KEY_RIGHT },
45 { 0x18, KEY_VIDEO }, /* Videos */
46 { 0x19, KEY_AUDIO }, /* Music */
47 /* 0x1a: Pictures - presume this means
48 "Multimedia Home Platform" -
49 no "PICTURES" key in input.h
50 */
51 { 0x1a, KEY_MHP },
52
53 { 0x1b, KEY_EPG }, /* Guide */
54 { 0x1c, KEY_TV },
55 { 0x1e, KEY_NEXTSONG }, /* skip >| */
56 { 0x1f, KEY_EXIT }, /* back/exit */
57 { 0x20, KEY_CHANNELUP }, /* channel / program + */
58 { 0x21, KEY_CHANNELDOWN }, /* channel / program - */
59 { 0x22, KEY_CHANNEL }, /* source (old black remote) */
60 { 0x24, KEY_PREVIOUSSONG }, /* replay |< */
61 { 0x25, KEY_ENTER }, /* OK */
62 { 0x26, KEY_SLEEP }, /* minimize (old black remote) */
63 { 0x29, KEY_BLUE }, /* blue key */
64 { 0x2e, KEY_GREEN }, /* green button */
65 { 0x30, KEY_PAUSE }, /* pause */
66 { 0x32, KEY_REWIND }, /* backward << */
67 { 0x34, KEY_FASTFORWARD }, /* forward >> */
68 { 0x35, KEY_PLAY },
69 { 0x36, KEY_STOP },
70 { 0x37, KEY_RECORD }, /* recording */
71 { 0x38, KEY_YELLOW }, /* yellow key */
72 { 0x3b, KEY_SELECT }, /* top right button */
73 { 0x3c, KEY_ZOOM }, /* full */
74 { 0x3d, KEY_POWER }, /* system power (green button) */
75};
76
77static struct rc_map_list hauppauge_new_map = {
78 .map = {
79 .scan = hauppauge_new,
80 .size = ARRAY_SIZE(hauppauge_new),
81 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
82 .name = RC_MAP_HAUPPAUGE_NEW,
83 }
84};
85
86static int __init init_rc_map_hauppauge_new(void)
87{
88 return rc_map_register(&hauppauge_new_map);
89}
90
91static void __exit exit_rc_map_hauppauge_new(void)
92{
93 rc_map_unregister(&hauppauge_new_map);
94}
95
96module_init(init_rc_map_hauppauge_new)
97module_exit(exit_rc_map_hauppauge_new)
98
99MODULE_LICENSE("GPL");
100MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c
new file mode 100644
index 000000000000..cb67184e015c
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-imon-mce.c
@@ -0,0 +1,142 @@
1/* rc5-imon-mce.c - Keytable for Windows Media Center RC-6 remotes for use
2 * with the SoundGraph iMON/Antec Veris hardware IR decoder
3 *
4 * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-map.h>
13
14/* mce-mode imon mce remote key table */
15static struct rc_map_table imon_mce[] = {
16 /* keys sorted mostly by frequency of use to optimize lookups */
17 { 0x800ff415, KEY_REWIND },
18 { 0x800ff414, KEY_FASTFORWARD },
19 { 0x800ff41b, KEY_PREVIOUS },
20 { 0x800ff41a, KEY_NEXT },
21
22 { 0x800ff416, KEY_PLAY },
23 { 0x800ff418, KEY_PAUSE },
24 { 0x800ff419, KEY_STOP },
25 { 0x800ff417, KEY_RECORD },
26
27 { 0x02000052, KEY_UP },
28 { 0x02000051, KEY_DOWN },
29 { 0x02000050, KEY_LEFT },
30 { 0x0200004f, KEY_RIGHT },
31
32 { 0x800ff41e, KEY_UP },
33 { 0x800ff41f, KEY_DOWN },
34 { 0x800ff420, KEY_LEFT },
35 { 0x800ff421, KEY_RIGHT },
36
37 /* 0x800ff40b also KEY_NUMERIC_POUND on some receivers */
38 { 0x800ff40b, KEY_ENTER },
39 { 0x02000028, KEY_ENTER },
40/* the OK and Enter buttons decode to the same value on some remotes
41 { 0x02000028, KEY_OK }, */
42 { 0x800ff422, KEY_OK },
43 { 0x0200002a, KEY_EXIT },
44 { 0x800ff423, KEY_EXIT },
45 { 0x02000029, KEY_DELETE },
46 /* 0x800ff40a also KEY_NUMERIC_STAR on some receivers */
47 { 0x800ff40a, KEY_DELETE },
48
49 { 0x800ff40e, KEY_MUTE },
50 { 0x800ff410, KEY_VOLUMEUP },
51 { 0x800ff411, KEY_VOLUMEDOWN },
52 { 0x800ff412, KEY_CHANNELUP },
53 { 0x800ff413, KEY_CHANNELDOWN },
54
55 { 0x0200001e, KEY_NUMERIC_1 },
56 { 0x0200001f, KEY_NUMERIC_2 },
57 { 0x02000020, KEY_NUMERIC_3 },
58 { 0x02000021, KEY_NUMERIC_4 },
59 { 0x02000022, KEY_NUMERIC_5 },
60 { 0x02000023, KEY_NUMERIC_6 },
61 { 0x02000024, KEY_NUMERIC_7 },
62 { 0x02000025, KEY_NUMERIC_8 },
63 { 0x02000026, KEY_NUMERIC_9 },
64 { 0x02000027, KEY_NUMERIC_0 },
65
66 { 0x800ff401, KEY_NUMERIC_1 },
67 { 0x800ff402, KEY_NUMERIC_2 },
68 { 0x800ff403, KEY_NUMERIC_3 },
69 { 0x800ff404, KEY_NUMERIC_4 },
70 { 0x800ff405, KEY_NUMERIC_5 },
71 { 0x800ff406, KEY_NUMERIC_6 },
72 { 0x800ff407, KEY_NUMERIC_7 },
73 { 0x800ff408, KEY_NUMERIC_8 },
74 { 0x800ff409, KEY_NUMERIC_9 },
75 { 0x800ff400, KEY_NUMERIC_0 },
76
77 { 0x02200025, KEY_NUMERIC_STAR },
78 { 0x02200020, KEY_NUMERIC_POUND },
79 /* 0x800ff41d also KEY_BLUE on some receivers */
80 { 0x800ff41d, KEY_NUMERIC_STAR },
81 /* 0x800ff41c also KEY_PREVIOUS on some receivers */
82 { 0x800ff41c, KEY_NUMERIC_POUND },
83
84 { 0x800ff446, KEY_TV },
85 { 0x800ff447, KEY_AUDIO }, /* My Music */
86 { 0x800ff448, KEY_PVR }, /* RecordedTV */
87 { 0x800ff449, KEY_CAMERA },
88 { 0x800ff44a, KEY_VIDEO },
89 /* 0x800ff424 also KEY_MENU on some receivers */
90 { 0x800ff424, KEY_DVD },
91 /* 0x800ff425 also KEY_GREEN on some receivers */
92 { 0x800ff425, KEY_TUNER }, /* LiveTV */
93 { 0x800ff450, KEY_RADIO },
94
95 { 0x800ff44c, KEY_LANGUAGE },
96 { 0x800ff427, KEY_ZOOM }, /* Aspect */
97
98 { 0x800ff45b, KEY_RED },
99 { 0x800ff45c, KEY_GREEN },
100 { 0x800ff45d, KEY_YELLOW },
101 { 0x800ff45e, KEY_BLUE },
102
103 { 0x800ff466, KEY_RED },
104 /* { 0x800ff425, KEY_GREEN }, */
105 { 0x800ff468, KEY_YELLOW },
106 /* { 0x800ff41d, KEY_BLUE }, */
107
108 { 0x800ff40f, KEY_INFO },
109 { 0x800ff426, KEY_EPG }, /* Guide */
110 { 0x800ff45a, KEY_SUBTITLE }, /* Caption/Teletext */
111 { 0x800ff44d, KEY_TITLE },
112
113 { 0x800ff40c, KEY_POWER },
114 { 0x800ff40d, KEY_PROG1 }, /* Windows MCE button */
115
116};
117
118static struct rc_map_list imon_mce_map = {
119 .map = {
120 .scan = imon_mce,
121 .size = ARRAY_SIZE(imon_mce),
122 /* its RC6, but w/a hardware decoder */
123 .rc_type = RC_TYPE_RC6,
124 .name = RC_MAP_IMON_MCE,
125 }
126};
127
128static int __init init_rc_map_imon_mce(void)
129{
130 return rc_map_register(&imon_mce_map);
131}
132
133static void __exit exit_rc_map_imon_mce(void)
134{
135 rc_map_unregister(&imon_mce_map);
136}
137
138module_init(init_rc_map_imon_mce)
139module_exit(exit_rc_map_imon_mce)
140
141MODULE_LICENSE("GPL");
142MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c
new file mode 100644
index 000000000000..eef46b73ca7b
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-imon-pad.c
@@ -0,0 +1,156 @@
1/* rc5-imon-pad.c - Keytable for SoundGraph iMON PAD and Antec Veris
2 * RM-200 Remote Control
3 *
4 * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-map.h>
13
14/*
15 * standard imon remote key table, which isn't really entirely
16 * "standard", as different receivers decode the same key on the
17 * same remote to different hex codes, and the silkscreened names
18 * vary a bit between the SoundGraph and Antec remotes... ugh.
19 */
20static struct rc_map_table imon_pad[] = {
21 /* keys sorted mostly by frequency of use to optimize lookups */
22 { 0x2a8195b7, KEY_REWIND },
23 { 0x298315b7, KEY_REWIND },
24 { 0x2b8115b7, KEY_FASTFORWARD },
25 { 0x2b8315b7, KEY_FASTFORWARD },
26 { 0x2b9115b7, KEY_PREVIOUS },
27 { 0x298195b7, KEY_NEXT },
28
29 { 0x2a8115b7, KEY_PLAY },
30 { 0x2a8315b7, KEY_PLAY },
31 { 0x2a9115b7, KEY_PAUSE },
32 { 0x2b9715b7, KEY_STOP },
33 { 0x298115b7, KEY_RECORD },
34
35 { 0x01008000, KEY_UP },
36 { 0x01007f00, KEY_DOWN },
37 { 0x01000080, KEY_LEFT },
38 { 0x0100007f, KEY_RIGHT },
39
40 { 0x2aa515b7, KEY_UP },
41 { 0x289515b7, KEY_DOWN },
42 { 0x29a515b7, KEY_LEFT },
43 { 0x2ba515b7, KEY_RIGHT },
44
45 { 0x0200002c, KEY_SPACE }, /* Select/Space */
46 { 0x2a9315b7, KEY_SPACE }, /* Select/Space */
47 { 0x02000028, KEY_ENTER },
48 { 0x28a195b7, KEY_ENTER },
49 { 0x288195b7, KEY_EXIT },
50 { 0x02000029, KEY_ESC },
51 { 0x2bb715b7, KEY_ESC },
52 { 0x0200002a, KEY_BACKSPACE },
53 { 0x28a115b7, KEY_BACKSPACE },
54
55 { 0x2b9595b7, KEY_MUTE },
56 { 0x28a395b7, KEY_VOLUMEUP },
57 { 0x28a595b7, KEY_VOLUMEDOWN },
58 { 0x289395b7, KEY_CHANNELUP },
59 { 0x288795b7, KEY_CHANNELDOWN },
60
61 { 0x0200001e, KEY_NUMERIC_1 },
62 { 0x0200001f, KEY_NUMERIC_2 },
63 { 0x02000020, KEY_NUMERIC_3 },
64 { 0x02000021, KEY_NUMERIC_4 },
65 { 0x02000022, KEY_NUMERIC_5 },
66 { 0x02000023, KEY_NUMERIC_6 },
67 { 0x02000024, KEY_NUMERIC_7 },
68 { 0x02000025, KEY_NUMERIC_8 },
69 { 0x02000026, KEY_NUMERIC_9 },
70 { 0x02000027, KEY_NUMERIC_0 },
71
72 { 0x28b595b7, KEY_NUMERIC_1 },
73 { 0x2bb195b7, KEY_NUMERIC_2 },
74 { 0x28b195b7, KEY_NUMERIC_3 },
75 { 0x2a8595b7, KEY_NUMERIC_4 },
76 { 0x299595b7, KEY_NUMERIC_5 },
77 { 0x2aa595b7, KEY_NUMERIC_6 },
78 { 0x2b9395b7, KEY_NUMERIC_7 },
79 { 0x2a8515b7, KEY_NUMERIC_8 },
80 { 0x2aa115b7, KEY_NUMERIC_9 },
81 { 0x2ba595b7, KEY_NUMERIC_0 },
82
83 { 0x02200025, KEY_NUMERIC_STAR },
84 { 0x28b515b7, KEY_NUMERIC_STAR },
85 { 0x02200020, KEY_NUMERIC_POUND },
86 { 0x29a115b7, KEY_NUMERIC_POUND },
87
88 { 0x2b8515b7, KEY_VIDEO },
89 { 0x299195b7, KEY_AUDIO },
90 { 0x2ba115b7, KEY_CAMERA },
91 { 0x28a515b7, KEY_TV },
92 { 0x29a395b7, KEY_DVD },
93 { 0x29a295b7, KEY_DVD },
94
95 /* the Menu key between DVD and Subtitle on the RM-200... */
96 { 0x2ba385b7, KEY_MENU },
97 { 0x2ba395b7, KEY_MENU },
98
99 { 0x288515b7, KEY_BOOKMARKS },
100 { 0x2ab715b7, KEY_MEDIA }, /* Thumbnail */
101 { 0x298595b7, KEY_SUBTITLE },
102 { 0x2b8595b7, KEY_LANGUAGE },
103
104 { 0x29a595b7, KEY_ZOOM },
105 { 0x2aa395b7, KEY_SCREEN }, /* FullScreen */
106
107 { 0x299115b7, KEY_KEYBOARD },
108 { 0x299135b7, KEY_KEYBOARD },
109
110 { 0x01010000, BTN_LEFT },
111 { 0x01020000, BTN_RIGHT },
112 { 0x01010080, BTN_LEFT },
113 { 0x01020080, BTN_RIGHT },
114 { 0x688301b7, BTN_LEFT },
115 { 0x688481b7, BTN_RIGHT },
116
117 { 0x2a9395b7, KEY_CYCLEWINDOWS }, /* TaskSwitcher */
118 { 0x2b8395b7, KEY_TIME }, /* Timer */
119
120 { 0x289115b7, KEY_POWER },
121 { 0x29b195b7, KEY_EJECTCD }, /* the one next to play */
122 { 0x299395b7, KEY_EJECTCLOSECD }, /* eject (by TaskSw) */
123
124 { 0x02800000, KEY_CONTEXT_MENU }, /* Left Menu */
125 { 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/
126 { 0x02000065, KEY_COMPOSE }, /* RightMenu */
127 { 0x28b715b7, KEY_COMPOSE }, /* RightMenu */
128 { 0x2ab195b7, KEY_PROG1 }, /* Go or MultiMon */
129 { 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */
130};
131
132static struct rc_map_list imon_pad_map = {
133 .map = {
134 .scan = imon_pad,
135 .size = ARRAY_SIZE(imon_pad),
136 /* actual protocol details unknown, hardware decoder */
137 .rc_type = RC_TYPE_OTHER,
138 .name = RC_MAP_IMON_PAD,
139 }
140};
141
142static int __init init_rc_map_imon_pad(void)
143{
144 return rc_map_register(&imon_pad_map);
145}
146
147static void __exit exit_rc_map_imon_pad(void)
148{
149 rc_map_unregister(&imon_pad_map);
150}
151
152module_init(init_rc_map_imon_pad)
153module_exit(exit_rc_map_imon_pad)
154
155MODULE_LICENSE("GPL");
156MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
new file mode 100644
index 000000000000..1f59e163f75d
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
@@ -0,0 +1,88 @@
1/* iodata-bctv7e.h - Keytable for iodata_bctv7e Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* IO-DATA BCTV7E Remote */
16
17static struct rc_map_table iodata_bctv7e[] = {
18 { 0x40, KEY_TV },
19 { 0x20, KEY_RADIO }, /* FM */
20 { 0x60, KEY_EPG },
21 { 0x00, KEY_POWER },
22
23 /* Keys 0 to 9 */
24 { 0x44, KEY_0 }, /* 10 */
25 { 0x50, KEY_1 },
26 { 0x30, KEY_2 },
27 { 0x70, KEY_3 },
28 { 0x48, KEY_4 },
29 { 0x28, KEY_5 },
30 { 0x68, KEY_6 },
31 { 0x58, KEY_7 },
32 { 0x38, KEY_8 },
33 { 0x78, KEY_9 },
34
35 { 0x10, KEY_L }, /* Live */
36 { 0x08, KEY_TIME }, /* Time Shift */
37
38 { 0x18, KEY_PLAYPAUSE }, /* Play */
39
40 { 0x24, KEY_ENTER }, /* 11 */
41 { 0x64, KEY_ESC }, /* 12 */
42 { 0x04, KEY_M }, /* Multi */
43
44 { 0x54, KEY_VIDEO },
45 { 0x34, KEY_CHANNELUP },
46 { 0x74, KEY_VOLUMEUP },
47 { 0x14, KEY_MUTE },
48
49 { 0x4c, KEY_VCR }, /* SVIDEO */
50 { 0x2c, KEY_CHANNELDOWN },
51 { 0x6c, KEY_VOLUMEDOWN },
52 { 0x0c, KEY_ZOOM },
53
54 { 0x5c, KEY_PAUSE },
55 { 0x3c, KEY_RED }, /* || (red) */
56 { 0x7c, KEY_RECORD }, /* recording */
57 { 0x1c, KEY_STOP },
58
59 { 0x41, KEY_REWIND }, /* backward << */
60 { 0x21, KEY_PLAY },
61 { 0x61, KEY_FASTFORWARD }, /* forward >> */
62 { 0x01, KEY_NEXT }, /* skip >| */
63};
64
65static struct rc_map_list iodata_bctv7e_map = {
66 .map = {
67 .scan = iodata_bctv7e,
68 .size = ARRAY_SIZE(iodata_bctv7e),
69 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
70 .name = RC_MAP_IODATA_BCTV7E,
71 }
72};
73
74static int __init init_rc_map_iodata_bctv7e(void)
75{
76 return rc_map_register(&iodata_bctv7e_map);
77}
78
79static void __exit exit_rc_map_iodata_bctv7e(void)
80{
81 rc_map_unregister(&iodata_bctv7e_map);
82}
83
84module_init(init_rc_map_iodata_bctv7e)
85module_exit(exit_rc_map_iodata_bctv7e)
86
87MODULE_LICENSE("GPL");
88MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c
new file mode 100644
index 000000000000..f31dc5c1ad9c
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-kaiomy.c
@@ -0,0 +1,87 @@
1/* kaiomy.h - Keytable for kaiomy Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Kaiomy TVnPC U2
16 Mauro Carvalho Chehab <mchehab@infradead.org>
17 */
18
19static struct rc_map_table kaiomy[] = {
20 { 0x43, KEY_POWER2},
21 { 0x01, KEY_LIST},
22 { 0x0b, KEY_ZOOM},
23 { 0x03, KEY_POWER},
24
25 { 0x04, KEY_1},
26 { 0x08, KEY_2},
27 { 0x02, KEY_3},
28
29 { 0x0f, KEY_4},
30 { 0x05, KEY_5},
31 { 0x06, KEY_6},
32
33 { 0x0c, KEY_7},
34 { 0x0d, KEY_8},
35 { 0x0a, KEY_9},
36
37 { 0x11, KEY_0},
38
39 { 0x09, KEY_CHANNELUP},
40 { 0x07, KEY_CHANNELDOWN},
41
42 { 0x0e, KEY_VOLUMEUP},
43 { 0x13, KEY_VOLUMEDOWN},
44
45 { 0x10, KEY_HOME},
46 { 0x12, KEY_ENTER},
47
48 { 0x14, KEY_RECORD},
49 { 0x15, KEY_STOP},
50 { 0x16, KEY_PLAY},
51 { 0x17, KEY_MUTE},
52
53 { 0x18, KEY_UP},
54 { 0x19, KEY_DOWN},
55 { 0x1a, KEY_LEFT},
56 { 0x1b, KEY_RIGHT},
57
58 { 0x1c, KEY_RED},
59 { 0x1d, KEY_GREEN},
60 { 0x1e, KEY_YELLOW},
61 { 0x1f, KEY_BLUE},
62};
63
64static struct rc_map_list kaiomy_map = {
65 .map = {
66 .scan = kaiomy,
67 .size = ARRAY_SIZE(kaiomy),
68 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
69 .name = RC_MAP_KAIOMY,
70 }
71};
72
73static int __init init_rc_map_kaiomy(void)
74{
75 return rc_map_register(&kaiomy_map);
76}
77
78static void __exit exit_rc_map_kaiomy(void)
79{
80 rc_map_unregister(&kaiomy_map);
81}
82
83module_init(init_rc_map_kaiomy)
84module_exit(exit_rc_map_kaiomy)
85
86MODULE_LICENSE("GPL");
87MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c
new file mode 100644
index 000000000000..3ce6ef79fc34
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-kworld-315u.c
@@ -0,0 +1,83 @@
1/* kworld-315u.h - Keytable for kworld_315u Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Kworld 315U
16 */
17
18static struct rc_map_table kworld_315u[] = {
19 { 0x6143, KEY_POWER },
20 { 0x6101, KEY_TUNER }, /* source */
21 { 0x610b, KEY_ZOOM },
22 { 0x6103, KEY_POWER2 }, /* shutdown */
23
24 { 0x6104, KEY_1 },
25 { 0x6108, KEY_2 },
26 { 0x6102, KEY_3 },
27 { 0x6109, KEY_CHANNELUP },
28
29 { 0x610f, KEY_4 },
30 { 0x6105, KEY_5 },
31 { 0x6106, KEY_6 },
32 { 0x6107, KEY_CHANNELDOWN },
33
34 { 0x610c, KEY_7 },
35 { 0x610d, KEY_8 },
36 { 0x610a, KEY_9 },
37 { 0x610e, KEY_VOLUMEUP },
38
39 { 0x6110, KEY_LAST },
40 { 0x6111, KEY_0 },
41 { 0x6112, KEY_ENTER },
42 { 0x6113, KEY_VOLUMEDOWN },
43
44 { 0x6114, KEY_RECORD },
45 { 0x6115, KEY_STOP },
46 { 0x6116, KEY_PLAY },
47 { 0x6117, KEY_MUTE },
48
49 { 0x6118, KEY_UP },
50 { 0x6119, KEY_DOWN },
51 { 0x611a, KEY_LEFT },
52 { 0x611b, KEY_RIGHT },
53
54 { 0x611c, KEY_RED },
55 { 0x611d, KEY_GREEN },
56 { 0x611e, KEY_YELLOW },
57 { 0x611f, KEY_BLUE },
58};
59
60static struct rc_map_list kworld_315u_map = {
61 .map = {
62 .scan = kworld_315u,
63 .size = ARRAY_SIZE(kworld_315u),
64 .rc_type = RC_TYPE_NEC,
65 .name = RC_MAP_KWORLD_315U,
66 }
67};
68
69static int __init init_rc_map_kworld_315u(void)
70{
71 return rc_map_register(&kworld_315u_map);
72}
73
74static void __exit exit_rc_map_kworld_315u(void)
75{
76 rc_map_unregister(&kworld_315u_map);
77}
78
79module_init(init_rc_map_kworld_315u)
80module_exit(exit_rc_map_kworld_315u)
81
82MODULE_LICENSE("GPL");
83MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
new file mode 100644
index 000000000000..e45f0b8759d0
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
@@ -0,0 +1,99 @@
1/* kworld-plus-tv-analog.h - Keytable for kworld_plus_tv_analog Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Kworld Plus TV Analog Lite PCI IR
16 Mauro Carvalho Chehab <mchehab@infradead.org>
17 */
18
19static struct rc_map_table kworld_plus_tv_analog[] = {
20 { 0x0c, KEY_PROG1 }, /* Kworld key */
21 { 0x16, KEY_CLOSECD }, /* -> ) */
22 { 0x1d, KEY_POWER2 },
23
24 { 0x00, KEY_1 },
25 { 0x01, KEY_2 },
26 { 0x02, KEY_3 }, /* Two keys have the same code: 3 and left */
27 { 0x03, KEY_4 }, /* Two keys have the same code: 3 and right */
28 { 0x04, KEY_5 },
29 { 0x05, KEY_6 },
30 { 0x06, KEY_7 },
31 { 0x07, KEY_8 },
32 { 0x08, KEY_9 },
33 { 0x0a, KEY_0 },
34
35 { 0x09, KEY_AGAIN },
36 { 0x14, KEY_MUTE },
37
38 { 0x20, KEY_UP },
39 { 0x21, KEY_DOWN },
40 { 0x0b, KEY_ENTER },
41
42 { 0x10, KEY_CHANNELUP },
43 { 0x11, KEY_CHANNELDOWN },
44
45 /* Couldn't map key left/key right since those
46 conflict with '3' and '4' scancodes
47 I dunno what the original driver does
48 */
49
50 { 0x13, KEY_VOLUMEUP },
51 { 0x12, KEY_VOLUMEDOWN },
52
53 /* The lower part of the IR
54 There are several duplicated keycodes there.
55 Most of them conflict with digits.
56 Add mappings just to the unused scancodes.
57 Somehow, the original driver has a way to know,
58 but this doesn't seem to be on some GPIO.
59 Also, it is not related to the time between keyup
60 and keydown.
61 */
62 { 0x19, KEY_TIME}, /* Timeshift */
63 { 0x1a, KEY_STOP},
64 { 0x1b, KEY_RECORD},
65
66 { 0x22, KEY_TEXT},
67
68 { 0x15, KEY_AUDIO}, /* ((*)) */
69 { 0x0f, KEY_ZOOM},
70 { 0x1c, KEY_CAMERA}, /* snapshot */
71
72 { 0x18, KEY_RED}, /* B */
73 { 0x23, KEY_GREEN}, /* C */
74};
75
76static struct rc_map_list kworld_plus_tv_analog_map = {
77 .map = {
78 .scan = kworld_plus_tv_analog,
79 .size = ARRAY_SIZE(kworld_plus_tv_analog),
80 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
81 .name = RC_MAP_KWORLD_PLUS_TV_ANALOG,
82 }
83};
84
85static int __init init_rc_map_kworld_plus_tv_analog(void)
86{
87 return rc_map_register(&kworld_plus_tv_analog_map);
88}
89
90static void __exit exit_rc_map_kworld_plus_tv_analog(void)
91{
92 rc_map_unregister(&kworld_plus_tv_analog_map);
93}
94
95module_init(init_rc_map_kworld_plus_tv_analog)
96module_exit(exit_rc_map_kworld_plus_tv_analog)
97
98MODULE_LICENSE("GPL");
99MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
new file mode 100644
index 000000000000..8faa54ff16e6
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
@@ -0,0 +1,99 @@
1/*
2 * LeadTek Y04G0051 remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23static struct rc_map_table leadtek_y04g0051[] = {
24 { 0x0300, KEY_POWER2 },
25 { 0x0303, KEY_SCREEN },
26 { 0x0304, KEY_RIGHT },
27 { 0x0305, KEY_1 },
28 { 0x0306, KEY_2 },
29 { 0x0307, KEY_3 },
30 { 0x0308, KEY_LEFT },
31 { 0x0309, KEY_4 },
32 { 0x030a, KEY_5 },
33 { 0x030b, KEY_6 },
34 { 0x030c, KEY_UP },
35 { 0x030d, KEY_7 },
36 { 0x030e, KEY_8 },
37 { 0x030f, KEY_9 },
38 { 0x0310, KEY_DOWN },
39 { 0x0311, KEY_AGAIN },
40 { 0x0312, KEY_0 },
41 { 0x0313, KEY_OK }, /* 1st ok */
42 { 0x0314, KEY_MUTE },
43 { 0x0316, KEY_OK }, /* 2nd ok */
44 { 0x031e, KEY_VIDEO }, /* 2nd video */
45 { 0x031b, KEY_AUDIO },
46 { 0x031f, KEY_TEXT },
47 { 0x0340, KEY_SLEEP },
48 { 0x0341, KEY_DOT },
49 { 0x0342, KEY_REWIND },
50 { 0x0343, KEY_PLAY },
51 { 0x0344, KEY_FASTFORWARD },
52 { 0x0345, KEY_TIME },
53 { 0x0346, KEY_STOP }, /* 2nd stop */
54 { 0x0347, KEY_RECORD },
55 { 0x0348, KEY_CAMERA },
56 { 0x0349, KEY_ESC },
57 { 0x034a, KEY_NEW },
58 { 0x034b, KEY_RED },
59 { 0x034c, KEY_GREEN },
60 { 0x034d, KEY_YELLOW },
61 { 0x034e, KEY_BLUE },
62 { 0x034f, KEY_MENU },
63 { 0x0350, KEY_STOP }, /* 1st stop */
64 { 0x0351, KEY_CHANNEL },
65 { 0x0352, KEY_VIDEO }, /* 1st video */
66 { 0x0353, KEY_EPG },
67 { 0x0354, KEY_PREVIOUS },
68 { 0x0355, KEY_NEXT },
69 { 0x0356, KEY_TV },
70 { 0x035a, KEY_VOLUMEDOWN },
71 { 0x035b, KEY_CHANNELUP },
72 { 0x035e, KEY_VOLUMEUP },
73 { 0x035f, KEY_CHANNELDOWN },
74};
75
76static struct rc_map_list leadtek_y04g0051_map = {
77 .map = {
78 .scan = leadtek_y04g0051,
79 .size = ARRAY_SIZE(leadtek_y04g0051),
80 .rc_type = RC_TYPE_NEC,
81 .name = RC_MAP_LEADTEK_Y04G0051,
82 }
83};
84
85static int __init init_rc_map_leadtek_y04g0051(void)
86{
87 return rc_map_register(&leadtek_y04g0051_map);
88}
89
90static void __exit exit_rc_map_leadtek_y04g0051(void)
91{
92 rc_map_unregister(&leadtek_y04g0051_map);
93}
94
95module_init(init_rc_map_leadtek_y04g0051)
96module_exit(exit_rc_map_leadtek_y04g0051)
97
98MODULE_LICENSE("GPL");
99MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c
new file mode 100644
index 000000000000..e8e23e233c39
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-lirc.c
@@ -0,0 +1,41 @@
1/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass
2 * all raw IR data to the lirc userspace decoder.
3 *
4 * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-core.h>
13
14static struct rc_map_table lirc[] = {
15 { },
16};
17
18static struct rc_map_list lirc_map = {
19 .map = {
20 .scan = lirc,
21 .size = ARRAY_SIZE(lirc),
22 .rc_type = RC_TYPE_LIRC,
23 .name = RC_MAP_LIRC,
24 }
25};
26
27static int __init init_rc_map_lirc(void)
28{
29 return rc_map_register(&lirc_map);
30}
31
32static void __exit exit_rc_map_lirc(void)
33{
34 rc_map_unregister(&lirc_map);
35}
36
37module_init(init_rc_map_lirc)
38module_exit(exit_rc_map_lirc)
39
40MODULE_LICENSE("GPL");
41MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c
new file mode 100644
index 000000000000..875cd81477c7
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-lme2510.c
@@ -0,0 +1,68 @@
1/* LME2510 remote control
2 *
3 *
4 * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-map.h>
13
14
15static struct rc_map_table lme2510_rc[] = {
16 { 0xba45, KEY_0 },
17 { 0xa05f, KEY_1 },
18 { 0xaf50, KEY_2 },
19 { 0xa25d, KEY_3 },
20 { 0xbe41, KEY_4 },
21 { 0xf50a, KEY_5 },
22 { 0xbd42, KEY_6 },
23 { 0xb847, KEY_7 },
24 { 0xb649, KEY_8 },
25 { 0xfa05, KEY_9 },
26 { 0xbc43, KEY_POWER },
27 { 0xb946, KEY_SUBTITLE },
28 { 0xf906, KEY_PAUSE },
29 { 0xfc03, KEY_MEDIA_REPEAT},
30 { 0xfd02, KEY_PAUSE },
31 { 0xa15e, KEY_VOLUMEUP },
32 { 0xa35c, KEY_VOLUMEDOWN },
33 { 0xf609, KEY_CHANNELUP },
34 { 0xe51a, KEY_CHANNELDOWN },
35 { 0xe11e, KEY_PLAY },
36 { 0xe41b, KEY_ZOOM },
37 { 0xa659, KEY_MUTE },
38 { 0xa55a, KEY_TV },
39 { 0xe718, KEY_RECORD },
40 { 0xf807, KEY_EPG },
41 { 0xfe01, KEY_STOP },
42
43};
44
45static struct rc_map_list lme2510_map = {
46 .map = {
47 .scan = lme2510_rc,
48 .size = ARRAY_SIZE(lme2510_rc),
49 .rc_type = RC_TYPE_UNKNOWN,
50 .name = RC_MAP_LME2510,
51 }
52};
53
54static int __init init_rc_lme2510_map(void)
55{
56 return rc_map_register(&lme2510_map);
57}
58
59static void __exit exit_rc_lme2510_map(void)
60{
61 rc_map_unregister(&lme2510_map);
62}
63
64module_init(init_rc_lme2510_map)
65module_exit(exit_rc_lme2510_map)
66
67MODULE_LICENSE("GPL");
68MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c
new file mode 100644
index 000000000000..23b2d04e7a9f
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-manli.c
@@ -0,0 +1,134 @@
1/* manli.h - Keytable for manli Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Michael Tokarev <mjt@tls.msk.ru>
16 keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at
17 least, and probably other cards too.
18 The "ascii-art picture" below (in comments, first row
19 is the keycode in hex, and subsequent row(s) shows
20 the button labels (several variants when appropriate)
21 helps to descide which keycodes to assign to the buttons.
22 */
23
24static struct rc_map_table manli[] = {
25
26 /* 0x1c 0x12 *
27 * FUNCTION POWER *
28 * FM (|) *
29 * */
30 { 0x1c, KEY_RADIO }, /*XXX*/
31 { 0x12, KEY_POWER },
32
33 /* 0x01 0x02 0x03 *
34 * 1 2 3 *
35 * *
36 * 0x04 0x05 0x06 *
37 * 4 5 6 *
38 * *
39 * 0x07 0x08 0x09 *
40 * 7 8 9 *
41 * */
42 { 0x01, KEY_1 },
43 { 0x02, KEY_2 },
44 { 0x03, KEY_3 },
45 { 0x04, KEY_4 },
46 { 0x05, KEY_5 },
47 { 0x06, KEY_6 },
48 { 0x07, KEY_7 },
49 { 0x08, KEY_8 },
50 { 0x09, KEY_9 },
51
52 /* 0x0a 0x00 0x17 *
53 * RECALL 0 +100 *
54 * PLUS *
55 * */
56 { 0x0a, KEY_AGAIN }, /*XXX KEY_REWIND? */
57 { 0x00, KEY_0 },
58 { 0x17, KEY_DIGITS }, /*XXX*/
59
60 /* 0x14 0x10 *
61 * MENU INFO *
62 * OSD */
63 { 0x14, KEY_MENU },
64 { 0x10, KEY_INFO },
65
66 /* 0x0b *
67 * Up *
68 * *
69 * 0x18 0x16 0x0c *
70 * Left Ok Right *
71 * *
72 * 0x015 *
73 * Down *
74 * */
75 { 0x0b, KEY_UP },
76 { 0x18, KEY_LEFT },
77 { 0x16, KEY_OK }, /*XXX KEY_SELECT? KEY_ENTER? */
78 { 0x0c, KEY_RIGHT },
79 { 0x15, KEY_DOWN },
80
81 /* 0x11 0x0d *
82 * TV/AV MODE *
83 * SOURCE STEREO *
84 * */
85 { 0x11, KEY_TV }, /*XXX*/
86 { 0x0d, KEY_MODE }, /*XXX there's no KEY_STEREO */
87
88 /* 0x0f 0x1b 0x1a *
89 * AUDIO Vol+ Chan+ *
90 * TIMESHIFT??? *
91 * *
92 * 0x0e 0x1f 0x1e *
93 * SLEEP Vol- Chan- *
94 * */
95 { 0x0f, KEY_AUDIO },
96 { 0x1b, KEY_VOLUMEUP },
97 { 0x1a, KEY_CHANNELUP },
98 { 0x0e, KEY_TIME },
99 { 0x1f, KEY_VOLUMEDOWN },
100 { 0x1e, KEY_CHANNELDOWN },
101
102 /* 0x13 0x19 *
103 * MUTE SNAPSHOT*
104 * */
105 { 0x13, KEY_MUTE },
106 { 0x19, KEY_CAMERA },
107
108 /* 0x1d unused ? */
109};
110
111static struct rc_map_list manli_map = {
112 .map = {
113 .scan = manli,
114 .size = ARRAY_SIZE(manli),
115 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
116 .name = RC_MAP_MANLI,
117 }
118};
119
120static int __init init_rc_map_manli(void)
121{
122 return rc_map_register(&manli_map);
123}
124
125static void __exit exit_rc_map_manli(void)
126{
127 rc_map_unregister(&manli_map);
128}
129
130module_init(init_rc_map_manli)
131module_exit(exit_rc_map_manli)
132
133MODULE_LICENSE("GPL");
134MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
new file mode 100644
index 000000000000..7b9a01b6e4cf
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
@@ -0,0 +1,67 @@
1/*
2 * MSI DIGIVOX mini II remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23static struct rc_map_table msi_digivox_ii[] = {
24 { 0x0002, KEY_2 },
25 { 0x0003, KEY_UP }, /* up */
26 { 0x0004, KEY_3 },
27 { 0x0005, KEY_CHANNELDOWN },
28 { 0x0008, KEY_5 },
29 { 0x0009, KEY_0 },
30 { 0x000b, KEY_8 },
31 { 0x000d, KEY_DOWN }, /* down */
32 { 0x0010, KEY_9 },
33 { 0x0011, KEY_7 },
34 { 0x0014, KEY_VOLUMEUP },
35 { 0x0015, KEY_CHANNELUP },
36 { 0x0016, KEY_OK },
37 { 0x0017, KEY_POWER2 },
38 { 0x001a, KEY_1 },
39 { 0x001c, KEY_4 },
40 { 0x001d, KEY_6 },
41 { 0x001f, KEY_VOLUMEDOWN },
42};
43
44static struct rc_map_list msi_digivox_ii_map = {
45 .map = {
46 .scan = msi_digivox_ii,
47 .size = ARRAY_SIZE(msi_digivox_ii),
48 .rc_type = RC_TYPE_NEC,
49 .name = RC_MAP_MSI_DIGIVOX_II,
50 }
51};
52
53static int __init init_rc_map_msi_digivox_ii(void)
54{
55 return rc_map_register(&msi_digivox_ii_map);
56}
57
58static void __exit exit_rc_map_msi_digivox_ii(void)
59{
60 rc_map_unregister(&msi_digivox_ii_map);
61}
62
63module_init(init_rc_map_msi_digivox_ii)
64module_exit(exit_rc_map_msi_digivox_ii)
65
66MODULE_LICENSE("GPL");
67MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
new file mode 100644
index 000000000000..ae9d06b39157
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
@@ -0,0 +1,85 @@
1/*
2 * MSI DIGIVOX mini III remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23/* MSI DIGIVOX mini III */
24/* Uses NEC extended 0x61d6. */
25/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote
26 since rc-kworld-315u.c lacks NEC extended address byte. */
27static struct rc_map_table msi_digivox_iii[] = {
28 { 0x61d601, KEY_VIDEO }, /* Source */
29 { 0x61d602, KEY_3 },
30 { 0x61d603, KEY_POWER }, /* ShutDown */
31 { 0x61d604, KEY_1 },
32 { 0x61d605, KEY_5 },
33 { 0x61d606, KEY_6 },
34 { 0x61d607, KEY_CHANNELDOWN }, /* CH- */
35 { 0x61d608, KEY_2 },
36 { 0x61d609, KEY_CHANNELUP }, /* CH+ */
37 { 0x61d60a, KEY_9 },
38 { 0x61d60b, KEY_ZOOM }, /* Zoom */
39 { 0x61d60c, KEY_7 },
40 { 0x61d60d, KEY_8 },
41 { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
42 { 0x61d60f, KEY_4 },
43 { 0x61d610, KEY_ESC }, /* [back up arrow] */
44 { 0x61d611, KEY_0 },
45 { 0x61d612, KEY_OK }, /* [enter arrow] */
46 { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
47 { 0x61d614, KEY_RECORD }, /* Rec */
48 { 0x61d615, KEY_STOP }, /* Stop */
49 { 0x61d616, KEY_PLAY }, /* Play */
50 { 0x61d617, KEY_MUTE }, /* Mute */
51 { 0x61d618, KEY_UP },
52 { 0x61d619, KEY_DOWN },
53 { 0x61d61a, KEY_LEFT },
54 { 0x61d61b, KEY_RIGHT },
55 { 0x61d61c, KEY_RED },
56 { 0x61d61d, KEY_GREEN },
57 { 0x61d61e, KEY_YELLOW },
58 { 0x61d61f, KEY_BLUE },
59 { 0x61d643, KEY_POWER2 }, /* [red power button] */
60};
61
62static struct rc_map_list msi_digivox_iii_map = {
63 .map = {
64 .scan = msi_digivox_iii,
65 .size = ARRAY_SIZE(msi_digivox_iii),
66 .rc_type = RC_TYPE_NEC,
67 .name = RC_MAP_MSI_DIGIVOX_III,
68 }
69};
70
71static int __init init_rc_map_msi_digivox_iii(void)
72{
73 return rc_map_register(&msi_digivox_iii_map);
74}
75
76static void __exit exit_rc_map_msi_digivox_iii(void)
77{
78 rc_map_unregister(&msi_digivox_iii_map);
79}
80
81module_init(init_rc_map_msi_digivox_iii)
82module_exit(exit_rc_map_msi_digivox_iii)
83
84MODULE_LICENSE("GPL");
85MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
new file mode 100644
index 000000000000..fa8fd0ab94c7
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
@@ -0,0 +1,123 @@
1/* msi-tvanywhere-plus.h - Keytable for msi_tvanywhere_plus Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 Keycodes for remote on the MSI TV@nywhere Plus. The controller IC on the card
17 is marked "KS003". The controller is I2C at address 0x30, but does not seem
18 to respond to probes until a read is performed from a valid device.
19 I don't know why...
20
21 Note: This remote may be of similar or identical design to the
22 Pixelview remote (?). The raw codes and duplicate button codes
23 appear to be the same.
24
25 Henry Wong <henry@stuffedcow.net>
26 Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
27*/
28
29static struct rc_map_table msi_tvanywhere_plus[] = {
30
31/* ---- Remote Button Layout ----
32
33 POWER SOURCE SCAN MUTE
34 TV/FM 1 2 3
35 |> 4 5 6
36 <| 7 8 9
37 ^^UP 0 + RECALL
38 vvDN RECORD STOP PLAY
39
40 MINIMIZE ZOOM
41
42 CH+
43 VOL- VOL+
44 CH-
45
46 SNAPSHOT MTS
47
48 << FUNC >> RESET
49*/
50
51 { 0x01, KEY_1 }, /* 1 */
52 { 0x0b, KEY_2 }, /* 2 */
53 { 0x1b, KEY_3 }, /* 3 */
54 { 0x05, KEY_4 }, /* 4 */
55 { 0x09, KEY_5 }, /* 5 */
56 { 0x15, KEY_6 }, /* 6 */
57 { 0x06, KEY_7 }, /* 7 */
58 { 0x0a, KEY_8 }, /* 8 */
59 { 0x12, KEY_9 }, /* 9 */
60 { 0x02, KEY_0 }, /* 0 */
61 { 0x10, KEY_KPPLUS }, /* + */
62 { 0x13, KEY_AGAIN }, /* Recall */
63
64 { 0x1e, KEY_POWER }, /* Power */
65 { 0x07, KEY_TUNER }, /* Source */
66 { 0x1c, KEY_SEARCH }, /* Scan */
67 { 0x18, KEY_MUTE }, /* Mute */
68
69 { 0x03, KEY_RADIO }, /* TV/FM */
70 /* The next four keys are duplicates that appear to send the
71 same IR code as Ch+, Ch-, >>, and << . The raw code assigned
72 to them is the actual code + 0x20 - they will never be
73 detected as such unless some way is discovered to distinguish
74 these buttons from those that have the same code. */
75 { 0x3f, KEY_RIGHT }, /* |> and Ch+ */
76 { 0x37, KEY_LEFT }, /* <| and Ch- */
77 { 0x2c, KEY_UP }, /* ^^Up and >> */
78 { 0x24, KEY_DOWN }, /* vvDn and << */
79
80 { 0x00, KEY_RECORD }, /* Record */
81 { 0x08, KEY_STOP }, /* Stop */
82 { 0x11, KEY_PLAY }, /* Play */
83
84 { 0x0f, KEY_CLOSE }, /* Minimize */
85 { 0x19, KEY_ZOOM }, /* Zoom */
86 { 0x1a, KEY_CAMERA }, /* Snapshot */
87 { 0x0d, KEY_LANGUAGE }, /* MTS */
88
89 { 0x14, KEY_VOLUMEDOWN }, /* Vol- */
90 { 0x16, KEY_VOLUMEUP }, /* Vol+ */
91 { 0x17, KEY_CHANNELDOWN }, /* Ch- */
92 { 0x1f, KEY_CHANNELUP }, /* Ch+ */
93
94 { 0x04, KEY_REWIND }, /* << */
95 { 0x0e, KEY_MENU }, /* Function */
96 { 0x0c, KEY_FASTFORWARD }, /* >> */
97 { 0x1d, KEY_RESTART }, /* Reset */
98};
99
100static struct rc_map_list msi_tvanywhere_plus_map = {
101 .map = {
102 .scan = msi_tvanywhere_plus,
103 .size = ARRAY_SIZE(msi_tvanywhere_plus),
104 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
105 .name = RC_MAP_MSI_TVANYWHERE_PLUS,
106 }
107};
108
109static int __init init_rc_map_msi_tvanywhere_plus(void)
110{
111 return rc_map_register(&msi_tvanywhere_plus_map);
112}
113
114static void __exit exit_rc_map_msi_tvanywhere_plus(void)
115{
116 rc_map_unregister(&msi_tvanywhere_plus_map);
117}
118
119module_init(init_rc_map_msi_tvanywhere_plus)
120module_exit(exit_rc_map_msi_tvanywhere_plus)
121
122MODULE_LICENSE("GPL");
123MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
new file mode 100644
index 000000000000..18b37facb0dd
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
@@ -0,0 +1,69 @@
1/* msi-tvanywhere.h - Keytable for msi_tvanywhere Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* MSI TV@nywhere MASTER remote */
16
17static struct rc_map_table msi_tvanywhere[] = {
18 /* Keys 0 to 9 */
19 { 0x00, KEY_0 },
20 { 0x01, KEY_1 },
21 { 0x02, KEY_2 },
22 { 0x03, KEY_3 },
23 { 0x04, KEY_4 },
24 { 0x05, KEY_5 },
25 { 0x06, KEY_6 },
26 { 0x07, KEY_7 },
27 { 0x08, KEY_8 },
28 { 0x09, KEY_9 },
29
30 { 0x0c, KEY_MUTE },
31 { 0x0f, KEY_SCREEN }, /* Full Screen */
32 { 0x10, KEY_FN }, /* Funtion */
33 { 0x11, KEY_TIME }, /* Time shift */
34 { 0x12, KEY_POWER },
35 { 0x13, KEY_MEDIA }, /* MTS */
36 { 0x14, KEY_SLOW },
37 { 0x16, KEY_REWIND }, /* backward << */
38 { 0x17, KEY_ENTER }, /* Return */
39 { 0x18, KEY_FASTFORWARD }, /* forward >> */
40 { 0x1a, KEY_CHANNELUP },
41 { 0x1b, KEY_VOLUMEUP },
42 { 0x1e, KEY_CHANNELDOWN },
43 { 0x1f, KEY_VOLUMEDOWN },
44};
45
46static struct rc_map_list msi_tvanywhere_map = {
47 .map = {
48 .scan = msi_tvanywhere,
49 .size = ARRAY_SIZE(msi_tvanywhere),
50 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
51 .name = RC_MAP_MSI_TVANYWHERE,
52 }
53};
54
55static int __init init_rc_map_msi_tvanywhere(void)
56{
57 return rc_map_register(&msi_tvanywhere_map);
58}
59
60static void __exit exit_rc_map_msi_tvanywhere(void)
61{
62 rc_map_unregister(&msi_tvanywhere_map);
63}
64
65module_init(init_rc_map_msi_tvanywhere)
66module_exit(exit_rc_map_msi_tvanywhere)
67
68MODULE_LICENSE("GPL");
69MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c
new file mode 100644
index 000000000000..3e6f077eb700
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-nebula.c
@@ -0,0 +1,96 @@
1/* nebula.h - Keytable for nebula Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table nebula[] = {
16 { 0x00, KEY_0 },
17 { 0x01, KEY_1 },
18 { 0x02, KEY_2 },
19 { 0x03, KEY_3 },
20 { 0x04, KEY_4 },
21 { 0x05, KEY_5 },
22 { 0x06, KEY_6 },
23 { 0x07, KEY_7 },
24 { 0x08, KEY_8 },
25 { 0x09, KEY_9 },
26 { 0x0a, KEY_TV },
27 { 0x0b, KEY_AUX },
28 { 0x0c, KEY_DVD },
29 { 0x0d, KEY_POWER },
30 { 0x0e, KEY_MHP }, /* labelled 'Picture' */
31 { 0x0f, KEY_AUDIO },
32 { 0x10, KEY_INFO },
33 { 0x11, KEY_F13 }, /* 16:9 */
34 { 0x12, KEY_F14 }, /* 14:9 */
35 { 0x13, KEY_EPG },
36 { 0x14, KEY_EXIT },
37 { 0x15, KEY_MENU },
38 { 0x16, KEY_UP },
39 { 0x17, KEY_DOWN },
40 { 0x18, KEY_LEFT },
41 { 0x19, KEY_RIGHT },
42 { 0x1a, KEY_ENTER },
43 { 0x1b, KEY_CHANNELUP },
44 { 0x1c, KEY_CHANNELDOWN },
45 { 0x1d, KEY_VOLUMEUP },
46 { 0x1e, KEY_VOLUMEDOWN },
47 { 0x1f, KEY_RED },
48 { 0x20, KEY_GREEN },
49 { 0x21, KEY_YELLOW },
50 { 0x22, KEY_BLUE },
51 { 0x23, KEY_SUBTITLE },
52 { 0x24, KEY_F15 }, /* AD */
53 { 0x25, KEY_TEXT },
54 { 0x26, KEY_MUTE },
55 { 0x27, KEY_REWIND },
56 { 0x28, KEY_STOP },
57 { 0x29, KEY_PLAY },
58 { 0x2a, KEY_FASTFORWARD },
59 { 0x2b, KEY_F16 }, /* chapter */
60 { 0x2c, KEY_PAUSE },
61 { 0x2d, KEY_PLAY },
62 { 0x2e, KEY_RECORD },
63 { 0x2f, KEY_F17 }, /* picture in picture */
64 { 0x30, KEY_KPPLUS }, /* zoom in */
65 { 0x31, KEY_KPMINUS }, /* zoom out */
66 { 0x32, KEY_F18 }, /* capture */
67 { 0x33, KEY_F19 }, /* web */
68 { 0x34, KEY_EMAIL },
69 { 0x35, KEY_PHONE },
70 { 0x36, KEY_PC },
71};
72
73static struct rc_map_list nebula_map = {
74 .map = {
75 .scan = nebula,
76 .size = ARRAY_SIZE(nebula),
77 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
78 .name = RC_MAP_NEBULA,
79 }
80};
81
82static int __init init_rc_map_nebula(void)
83{
84 return rc_map_register(&nebula_map);
85}
86
87static void __exit exit_rc_map_nebula(void)
88{
89 rc_map_unregister(&nebula_map);
90}
91
92module_init(init_rc_map_nebula)
93module_exit(exit_rc_map_nebula)
94
95MODULE_LICENSE("GPL");
96MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
new file mode 100644
index 000000000000..26f114c5c0de
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -0,0 +1,105 @@
1/* nec-terratec-cinergy-xs.h - Keytable for nec_terratec_cinergy_xs Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Terratec Cinergy Hybrid T USB XS FM
16 Mauro Carvalho Chehab <mchehab@redhat.com>
17 */
18
19static struct rc_map_table nec_terratec_cinergy_xs[] = {
20 { 0x1441, KEY_HOME},
21 { 0x1401, KEY_POWER2},
22
23 { 0x1442, KEY_MENU}, /* DVD menu */
24 { 0x1443, KEY_SUBTITLE},
25 { 0x1444, KEY_TEXT}, /* Teletext */
26 { 0x1445, KEY_DELETE},
27
28 { 0x1402, KEY_1},
29 { 0x1403, KEY_2},
30 { 0x1404, KEY_3},
31 { 0x1405, KEY_4},
32 { 0x1406, KEY_5},
33 { 0x1407, KEY_6},
34 { 0x1408, KEY_7},
35 { 0x1409, KEY_8},
36 { 0x140a, KEY_9},
37 { 0x140c, KEY_0},
38
39 { 0x140b, KEY_TUNER}, /* AV */
40 { 0x140d, KEY_MODE}, /* A.B */
41
42 { 0x1446, KEY_TV},
43 { 0x1447, KEY_DVD},
44 { 0x1449, KEY_VIDEO},
45 { 0x144a, KEY_RADIO}, /* Music */
46 { 0x144b, KEY_CAMERA}, /* PIC */
47
48 { 0x1410, KEY_UP},
49 { 0x1411, KEY_LEFT},
50 { 0x1412, KEY_OK},
51 { 0x1413, KEY_RIGHT},
52 { 0x1414, KEY_DOWN},
53
54 { 0x140f, KEY_EPG},
55 { 0x1416, KEY_INFO},
56 { 0x144d, KEY_BACKSPACE},
57
58 { 0x141c, KEY_VOLUMEUP},
59 { 0x141e, KEY_VOLUMEDOWN},
60
61 { 0x144c, KEY_PLAY},
62 { 0x141d, KEY_MUTE},
63
64 { 0x141b, KEY_CHANNELUP},
65 { 0x141f, KEY_CHANNELDOWN},
66
67 { 0x1417, KEY_RED},
68 { 0x1418, KEY_GREEN},
69 { 0x1419, KEY_YELLOW},
70 { 0x141a, KEY_BLUE},
71
72 { 0x1458, KEY_RECORD},
73 { 0x1448, KEY_STOP},
74 { 0x1440, KEY_PAUSE},
75
76 { 0x1454, KEY_LAST},
77 { 0x144e, KEY_REWIND},
78 { 0x144f, KEY_FASTFORWARD},
79 { 0x145c, KEY_NEXT},
80};
81
82static struct rc_map_list nec_terratec_cinergy_xs_map = {
83 .map = {
84 .scan = nec_terratec_cinergy_xs,
85 .size = ARRAY_SIZE(nec_terratec_cinergy_xs),
86 .rc_type = RC_TYPE_NEC,
87 .name = RC_MAP_NEC_TERRATEC_CINERGY_XS,
88 }
89};
90
91static int __init init_rc_map_nec_terratec_cinergy_xs(void)
92{
93 return rc_map_register(&nec_terratec_cinergy_xs_map);
94}
95
96static void __exit exit_rc_map_nec_terratec_cinergy_xs(void)
97{
98 rc_map_unregister(&nec_terratec_cinergy_xs_map);
99}
100
101module_init(init_rc_map_nec_terratec_cinergy_xs)
102module_exit(exit_rc_map_nec_terratec_cinergy_xs)
103
104MODULE_LICENSE("GPL");
105MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c
new file mode 100644
index 000000000000..629ee9d84537
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-norwood.c
@@ -0,0 +1,85 @@
1/* norwood.h - Keytable for norwood Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Norwood Micro (non-Pro) TV Tuner
16 By Peter Naulls <peter@chocky.org>
17 Key comments are the functions given in the manual */
18
19static struct rc_map_table norwood[] = {
20 /* Keys 0 to 9 */
21 { 0x20, KEY_0 },
22 { 0x21, KEY_1 },
23 { 0x22, KEY_2 },
24 { 0x23, KEY_3 },
25 { 0x24, KEY_4 },
26 { 0x25, KEY_5 },
27 { 0x26, KEY_6 },
28 { 0x27, KEY_7 },
29 { 0x28, KEY_8 },
30 { 0x29, KEY_9 },
31
32 { 0x78, KEY_TUNER }, /* Video Source */
33 { 0x2c, KEY_EXIT }, /* Open/Close software */
34 { 0x2a, KEY_SELECT }, /* 2 Digit Select */
35 { 0x69, KEY_AGAIN }, /* Recall */
36
37 { 0x32, KEY_BRIGHTNESSUP }, /* Brightness increase */
38 { 0x33, KEY_BRIGHTNESSDOWN }, /* Brightness decrease */
39 { 0x6b, KEY_KPPLUS }, /* (not named >>>>>) */
40 { 0x6c, KEY_KPMINUS }, /* (not named <<<<<) */
41
42 { 0x2d, KEY_MUTE }, /* Mute */
43 { 0x30, KEY_VOLUMEUP }, /* Volume up */
44 { 0x31, KEY_VOLUMEDOWN }, /* Volume down */
45 { 0x60, KEY_CHANNELUP }, /* Channel up */
46 { 0x61, KEY_CHANNELDOWN }, /* Channel down */
47
48 { 0x3f, KEY_RECORD }, /* Record */
49 { 0x37, KEY_PLAY }, /* Play */
50 { 0x36, KEY_PAUSE }, /* Pause */
51 { 0x2b, KEY_STOP }, /* Stop */
52 { 0x67, KEY_FASTFORWARD }, /* Foward */
53 { 0x66, KEY_REWIND }, /* Rewind */
54 { 0x3e, KEY_SEARCH }, /* Auto Scan */
55 { 0x2e, KEY_CAMERA }, /* Capture Video */
56 { 0x6d, KEY_MENU }, /* Show/Hide Control */
57 { 0x2f, KEY_ZOOM }, /* Full Screen */
58 { 0x34, KEY_RADIO }, /* FM */
59 { 0x65, KEY_POWER }, /* Computer power */
60};
61
62static struct rc_map_list norwood_map = {
63 .map = {
64 .scan = norwood,
65 .size = ARRAY_SIZE(norwood),
66 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
67 .name = RC_MAP_NORWOOD,
68 }
69};
70
71static int __init init_rc_map_norwood(void)
72{
73 return rc_map_register(&norwood_map);
74}
75
76static void __exit exit_rc_map_norwood(void)
77{
78 rc_map_unregister(&norwood_map);
79}
80
81module_init(init_rc_map_norwood)
82module_exit(exit_rc_map_norwood)
83
84MODULE_LICENSE("GPL");
85MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c
new file mode 100644
index 000000000000..4aa588bf6d69
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-npgtech.c
@@ -0,0 +1,80 @@
1/* npgtech.h - Keytable for npgtech Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table npgtech[] = {
16 { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */
17 { 0x2a, KEY_FRONT },
18
19 { 0x3e, KEY_1 },
20 { 0x02, KEY_2 },
21 { 0x06, KEY_3 },
22 { 0x0a, KEY_4 },
23 { 0x0e, KEY_5 },
24 { 0x12, KEY_6 },
25 { 0x16, KEY_7 },
26 { 0x1a, KEY_8 },
27 { 0x1e, KEY_9 },
28 { 0x3a, KEY_0 },
29 { 0x22, KEY_NUMLOCK }, /* -/-- */
30 { 0x20, KEY_REFRESH },
31
32 { 0x03, KEY_BRIGHTNESSDOWN },
33 { 0x28, KEY_AUDIO },
34 { 0x3c, KEY_CHANNELUP },
35 { 0x3f, KEY_VOLUMEDOWN },
36 { 0x2e, KEY_MUTE },
37 { 0x3b, KEY_VOLUMEUP },
38 { 0x00, KEY_CHANNELDOWN },
39 { 0x07, KEY_BRIGHTNESSUP },
40 { 0x2c, KEY_TEXT },
41
42 { 0x37, KEY_RECORD },
43 { 0x17, KEY_PLAY },
44 { 0x13, KEY_PAUSE },
45 { 0x26, KEY_STOP },
46 { 0x18, KEY_FASTFORWARD },
47 { 0x14, KEY_REWIND },
48 { 0x33, KEY_ZOOM },
49 { 0x32, KEY_KEYBOARD },
50 { 0x30, KEY_GOTO }, /* Pointing arrow */
51 { 0x36, KEY_MACRO }, /* Maximize/Minimize (yellow) */
52 { 0x0b, KEY_RADIO },
53 { 0x10, KEY_POWER },
54
55};
56
57static struct rc_map_list npgtech_map = {
58 .map = {
59 .scan = npgtech,
60 .size = ARRAY_SIZE(npgtech),
61 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
62 .name = RC_MAP_NPGTECH,
63 }
64};
65
66static int __init init_rc_map_npgtech(void)
67{
68 return rc_map_register(&npgtech_map);
69}
70
71static void __exit exit_rc_map_npgtech(void)
72{
73 rc_map_unregister(&npgtech_map);
74}
75
76module_init(init_rc_map_npgtech)
77module_exit(exit_rc_map_npgtech)
78
79MODULE_LICENSE("GPL");
80MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c
new file mode 100644
index 000000000000..fa5ae5981eb8
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c
@@ -0,0 +1,80 @@
1/* pctv-sedna.h - Keytable for pctv_sedna Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Mapping for the 28 key remote control as seen at
16 http://www.sednacomputer.com/photo/cardbus-tv.jpg
17 Pavel Mihaylov <bin@bash.info>
18 Also for the remote bundled with Kozumi KTV-01C card */
19
20static struct rc_map_table pctv_sedna[] = {
21 { 0x00, KEY_0 },
22 { 0x01, KEY_1 },
23 { 0x02, KEY_2 },
24 { 0x03, KEY_3 },
25 { 0x04, KEY_4 },
26 { 0x05, KEY_5 },
27 { 0x06, KEY_6 },
28 { 0x07, KEY_7 },
29 { 0x08, KEY_8 },
30 { 0x09, KEY_9 },
31
32 { 0x0a, KEY_AGAIN }, /* Recall */
33 { 0x0b, KEY_CHANNELUP },
34 { 0x0c, KEY_VOLUMEUP },
35 { 0x0d, KEY_MODE }, /* Stereo */
36 { 0x0e, KEY_STOP },
37 { 0x0f, KEY_PREVIOUSSONG },
38 { 0x10, KEY_ZOOM },
39 { 0x11, KEY_TUNER }, /* Source */
40 { 0x12, KEY_POWER },
41 { 0x13, KEY_MUTE },
42 { 0x15, KEY_CHANNELDOWN },
43 { 0x18, KEY_VOLUMEDOWN },
44 { 0x19, KEY_CAMERA }, /* Snapshot */
45 { 0x1a, KEY_NEXTSONG },
46 { 0x1b, KEY_TIME }, /* Time Shift */
47 { 0x1c, KEY_RADIO }, /* FM Radio */
48 { 0x1d, KEY_RECORD },
49 { 0x1e, KEY_PAUSE },
50 /* additional codes for Kozumi's remote */
51 { 0x14, KEY_INFO }, /* OSD */
52 { 0x16, KEY_OK }, /* OK */
53 { 0x17, KEY_DIGITS }, /* Plus */
54 { 0x1f, KEY_PLAY }, /* Play */
55};
56
57static struct rc_map_list pctv_sedna_map = {
58 .map = {
59 .scan = pctv_sedna,
60 .size = ARRAY_SIZE(pctv_sedna),
61 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
62 .name = RC_MAP_PCTV_SEDNA,
63 }
64};
65
66static int __init init_rc_map_pctv_sedna(void)
67{
68 return rc_map_register(&pctv_sedna_map);
69}
70
71static void __exit exit_rc_map_pctv_sedna(void)
72{
73 rc_map_unregister(&pctv_sedna_map);
74}
75
76module_init(init_rc_map_pctv_sedna)
77module_exit(exit_rc_map_pctv_sedna)
78
79MODULE_LICENSE("GPL");
80MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c
new file mode 100644
index 000000000000..23b8c505c6aa
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c
@@ -0,0 +1,94 @@
1/* pinnacle-color.h - Keytable for pinnacle_color Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table pinnacle_color[] = {
16 { 0x59, KEY_MUTE },
17 { 0x4a, KEY_POWER },
18
19 { 0x18, KEY_TEXT },
20 { 0x26, KEY_TV },
21 { 0x3d, KEY_PRINT },
22
23 { 0x48, KEY_RED },
24 { 0x04, KEY_GREEN },
25 { 0x11, KEY_YELLOW },
26 { 0x00, KEY_BLUE },
27
28 { 0x2d, KEY_VOLUMEUP },
29 { 0x1e, KEY_VOLUMEDOWN },
30
31 { 0x49, KEY_MENU },
32
33 { 0x16, KEY_CHANNELUP },
34 { 0x17, KEY_CHANNELDOWN },
35
36 { 0x20, KEY_UP },
37 { 0x21, KEY_DOWN },
38 { 0x22, KEY_LEFT },
39 { 0x23, KEY_RIGHT },
40 { 0x0d, KEY_SELECT },
41
42 { 0x08, KEY_BACK },
43 { 0x07, KEY_REFRESH },
44
45 { 0x2f, KEY_ZOOM },
46 { 0x29, KEY_RECORD },
47
48 { 0x4b, KEY_PAUSE },
49 { 0x4d, KEY_REWIND },
50 { 0x2e, KEY_PLAY },
51 { 0x4e, KEY_FORWARD },
52 { 0x53, KEY_PREVIOUS },
53 { 0x4c, KEY_STOP },
54 { 0x54, KEY_NEXT },
55
56 { 0x69, KEY_0 },
57 { 0x6a, KEY_1 },
58 { 0x6b, KEY_2 },
59 { 0x6c, KEY_3 },
60 { 0x6d, KEY_4 },
61 { 0x6e, KEY_5 },
62 { 0x6f, KEY_6 },
63 { 0x70, KEY_7 },
64 { 0x71, KEY_8 },
65 { 0x72, KEY_9 },
66
67 { 0x74, KEY_CHANNEL },
68 { 0x0a, KEY_BACKSPACE },
69};
70
71static struct rc_map_list pinnacle_color_map = {
72 .map = {
73 .scan = pinnacle_color,
74 .size = ARRAY_SIZE(pinnacle_color),
75 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
76 .name = RC_MAP_PINNACLE_COLOR,
77 }
78};
79
80static int __init init_rc_map_pinnacle_color(void)
81{
82 return rc_map_register(&pinnacle_color_map);
83}
84
85static void __exit exit_rc_map_pinnacle_color(void)
86{
87 rc_map_unregister(&pinnacle_color_map);
88}
89
90module_init(init_rc_map_pinnacle_color)
91module_exit(exit_rc_map_pinnacle_color)
92
93MODULE_LICENSE("GPL");
94MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
new file mode 100644
index 000000000000..6ba8c368d10a
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
@@ -0,0 +1,89 @@
1/* pinnacle-grey.h - Keytable for pinnacle_grey Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table pinnacle_grey[] = {
16 { 0x3a, KEY_0 },
17 { 0x31, KEY_1 },
18 { 0x32, KEY_2 },
19 { 0x33, KEY_3 },
20 { 0x34, KEY_4 },
21 { 0x35, KEY_5 },
22 { 0x36, KEY_6 },
23 { 0x37, KEY_7 },
24 { 0x38, KEY_8 },
25 { 0x39, KEY_9 },
26
27 { 0x2f, KEY_POWER },
28
29 { 0x2e, KEY_P },
30 { 0x1f, KEY_L },
31 { 0x2b, KEY_I },
32
33 { 0x2d, KEY_SCREEN },
34 { 0x1e, KEY_ZOOM },
35 { 0x1b, KEY_VOLUMEUP },
36 { 0x0f, KEY_VOLUMEDOWN },
37 { 0x17, KEY_CHANNELUP },
38 { 0x1c, KEY_CHANNELDOWN },
39 { 0x25, KEY_INFO },
40
41 { 0x3c, KEY_MUTE },
42
43 { 0x3d, KEY_LEFT },
44 { 0x3b, KEY_RIGHT },
45
46 { 0x3f, KEY_UP },
47 { 0x3e, KEY_DOWN },
48 { 0x1a, KEY_ENTER },
49
50 { 0x1d, KEY_MENU },
51 { 0x19, KEY_AGAIN },
52 { 0x16, KEY_PREVIOUSSONG },
53 { 0x13, KEY_NEXTSONG },
54 { 0x15, KEY_PAUSE },
55 { 0x0e, KEY_REWIND },
56 { 0x0d, KEY_PLAY },
57 { 0x0b, KEY_STOP },
58 { 0x07, KEY_FORWARD },
59 { 0x27, KEY_RECORD },
60 { 0x26, KEY_TUNER },
61 { 0x29, KEY_TEXT },
62 { 0x2a, KEY_MEDIA },
63 { 0x18, KEY_EPG },
64};
65
66static struct rc_map_list pinnacle_grey_map = {
67 .map = {
68 .scan = pinnacle_grey,
69 .size = ARRAY_SIZE(pinnacle_grey),
70 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
71 .name = RC_MAP_PINNACLE_GREY,
72 }
73};
74
75static int __init init_rc_map_pinnacle_grey(void)
76{
77 return rc_map_register(&pinnacle_grey_map);
78}
79
80static void __exit exit_rc_map_pinnacle_grey(void)
81{
82 rc_map_unregister(&pinnacle_grey_map);
83}
84
85module_init(init_rc_map_pinnacle_grey)
86module_exit(exit_rc_map_pinnacle_grey)
87
88MODULE_LICENSE("GPL");
89MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
new file mode 100644
index 000000000000..bb10ffe086b4
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
@@ -0,0 +1,73 @@
1/* pinnacle-pctv-hd.h - Keytable for pinnacle_pctv_hd Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Pinnacle PCTV HD 800i mini remote */
16
17static struct rc_map_table pinnacle_pctv_hd[] = {
18
19 { 0x0f, KEY_1 },
20 { 0x15, KEY_2 },
21 { 0x10, KEY_3 },
22 { 0x18, KEY_4 },
23 { 0x1b, KEY_5 },
24 { 0x1e, KEY_6 },
25 { 0x11, KEY_7 },
26 { 0x21, KEY_8 },
27 { 0x12, KEY_9 },
28 { 0x27, KEY_0 },
29
30 { 0x24, KEY_ZOOM },
31 { 0x2a, KEY_SUBTITLE },
32
33 { 0x00, KEY_MUTE },
34 { 0x01, KEY_ENTER }, /* Pinnacle Logo */
35 { 0x39, KEY_POWER },
36
37 { 0x03, KEY_VOLUMEUP },
38 { 0x09, KEY_VOLUMEDOWN },
39 { 0x06, KEY_CHANNELUP },
40 { 0x0c, KEY_CHANNELDOWN },
41
42 { 0x2d, KEY_REWIND },
43 { 0x30, KEY_PLAYPAUSE },
44 { 0x33, KEY_FASTFORWARD },
45 { 0x3c, KEY_STOP },
46 { 0x36, KEY_RECORD },
47 { 0x3f, KEY_EPG }, /* Labeled "?" */
48};
49
50static struct rc_map_list pinnacle_pctv_hd_map = {
51 .map = {
52 .scan = pinnacle_pctv_hd,
53 .size = ARRAY_SIZE(pinnacle_pctv_hd),
54 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
55 .name = RC_MAP_PINNACLE_PCTV_HD,
56 }
57};
58
59static int __init init_rc_map_pinnacle_pctv_hd(void)
60{
61 return rc_map_register(&pinnacle_pctv_hd_map);
62}
63
64static void __exit exit_rc_map_pinnacle_pctv_hd(void)
65{
66 rc_map_unregister(&pinnacle_pctv_hd_map);
67}
68
69module_init(init_rc_map_pinnacle_pctv_hd)
70module_exit(exit_rc_map_pinnacle_pctv_hd)
71
72MODULE_LICENSE("GPL");
73MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c
new file mode 100644
index 000000000000..e5ab071f635a
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c
@@ -0,0 +1,77 @@
1/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 * Keytable for 002-T IR remote provided together with Pixelview
17 * SBTVD Hybrid Remote Controller. Uses NEC extended format.
18 */
19static struct rc_map_table pixelview_002t[] = {
20 { 0x866b13, KEY_MUTE },
21 { 0x866b12, KEY_POWER2 }, /* power */
22
23 { 0x866b01, KEY_1 },
24 { 0x866b02, KEY_2 },
25 { 0x866b03, KEY_3 },
26 { 0x866b04, KEY_4 },
27 { 0x866b05, KEY_5 },
28 { 0x866b06, KEY_6 },
29 { 0x866b07, KEY_7 },
30 { 0x866b08, KEY_8 },
31 { 0x866b09, KEY_9 },
32 { 0x866b00, KEY_0 },
33
34 { 0x866b0d, KEY_CHANNELUP },
35 { 0x866b19, KEY_CHANNELDOWN },
36 { 0x866b10, KEY_VOLUMEUP }, /* vol + */
37 { 0x866b0c, KEY_VOLUMEDOWN }, /* vol - */
38
39 { 0x866b0a, KEY_CAMERA }, /* snapshot */
40 { 0x866b0b, KEY_ZOOM }, /* zoom */
41
42 { 0x866b1b, KEY_BACKSPACE },
43 { 0x866b15, KEY_ENTER },
44
45 { 0x866b1d, KEY_UP },
46 { 0x866b1e, KEY_DOWN },
47 { 0x866b0e, KEY_LEFT },
48 { 0x866b0f, KEY_RIGHT },
49
50 { 0x866b18, KEY_RECORD },
51 { 0x866b1a, KEY_STOP },
52};
53
54static struct rc_map_list pixelview_map = {
55 .map = {
56 .scan = pixelview_002t,
57 .size = ARRAY_SIZE(pixelview_002t),
58 .rc_type = RC_TYPE_NEC,
59 .name = RC_MAP_PIXELVIEW_002T,
60 }
61};
62
63static int __init init_rc_map_pixelview(void)
64{
65 return rc_map_register(&pixelview_map);
66}
67
68static void __exit exit_rc_map_pixelview(void)
69{
70 rc_map_unregister(&pixelview_map);
71}
72
73module_init(init_rc_map_pixelview)
74module_exit(exit_rc_map_pixelview)
75
76MODULE_LICENSE("GPL");
77MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
new file mode 100644
index 000000000000..8d9f664e0a2d
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
@@ -0,0 +1,83 @@
1/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 * Keytable for MK-F12 IR remote provided together with Pixelview
17 * Ultra Pro Remote Controller. Uses NEC extended format.
18 */
19static struct rc_map_table pixelview_mk12[] = {
20 { 0x866b03, KEY_TUNER }, /* Timeshift */
21 { 0x866b1e, KEY_POWER2 }, /* power */
22
23 { 0x866b01, KEY_1 },
24 { 0x866b0b, KEY_2 },
25 { 0x866b1b, KEY_3 },
26 { 0x866b05, KEY_4 },
27 { 0x866b09, KEY_5 },
28 { 0x866b15, KEY_6 },
29 { 0x866b06, KEY_7 },
30 { 0x866b0a, KEY_8 },
31 { 0x866b12, KEY_9 },
32 { 0x866b02, KEY_0 },
33
34 { 0x866b13, KEY_AGAIN }, /* loop */
35 { 0x866b10, KEY_DIGITS }, /* +100 */
36
37 { 0x866b00, KEY_MEDIA }, /* source */
38 { 0x866b18, KEY_MUTE }, /* mute */
39 { 0x866b19, KEY_CAMERA }, /* snapshot */
40 { 0x866b1a, KEY_SEARCH }, /* scan */
41
42 { 0x866b16, KEY_CHANNELUP }, /* chn + */
43 { 0x866b14, KEY_CHANNELDOWN }, /* chn - */
44 { 0x866b1f, KEY_VOLUMEUP }, /* vol + */
45 { 0x866b17, KEY_VOLUMEDOWN }, /* vol - */
46 { 0x866b1c, KEY_ZOOM }, /* zoom */
47
48 { 0x866b04, KEY_REWIND },
49 { 0x866b0e, KEY_RECORD },
50 { 0x866b0c, KEY_FORWARD },
51
52 { 0x866b1d, KEY_STOP },
53 { 0x866b08, KEY_PLAY },
54 { 0x866b0f, KEY_PAUSE },
55
56 { 0x866b0d, KEY_TV },
57 { 0x866b07, KEY_RADIO }, /* FM */
58};
59
60static struct rc_map_list pixelview_map = {
61 .map = {
62 .scan = pixelview_mk12,
63 .size = ARRAY_SIZE(pixelview_mk12),
64 .rc_type = RC_TYPE_NEC,
65 .name = RC_MAP_PIXELVIEW_MK12,
66 }
67};
68
69static int __init init_rc_map_pixelview(void)
70{
71 return rc_map_register(&pixelview_map);
72}
73
74static void __exit exit_rc_map_pixelview(void)
75{
76 rc_map_unregister(&pixelview_map);
77}
78
79module_init(init_rc_map_pixelview)
80module_exit(exit_rc_map_pixelview)
81
82MODULE_LICENSE("GPL");
83MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c
new file mode 100644
index 000000000000..777a70076be2
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pixelview-new.c
@@ -0,0 +1,83 @@
1/* pixelview-new.h - Keytable for pixelview_new Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 Mauro Carvalho Chehab <mchehab@infradead.org>
17 present on PV MPEG 8000GT
18 */
19
20static struct rc_map_table pixelview_new[] = {
21 { 0x3c, KEY_TIME }, /* Timeshift */
22 { 0x12, KEY_POWER },
23
24 { 0x3d, KEY_1 },
25 { 0x38, KEY_2 },
26 { 0x18, KEY_3 },
27 { 0x35, KEY_4 },
28 { 0x39, KEY_5 },
29 { 0x15, KEY_6 },
30 { 0x36, KEY_7 },
31 { 0x3a, KEY_8 },
32 { 0x1e, KEY_9 },
33 { 0x3e, KEY_0 },
34
35 { 0x1c, KEY_AGAIN }, /* LOOP */
36 { 0x3f, KEY_MEDIA }, /* Source */
37 { 0x1f, KEY_LAST }, /* +100 */
38 { 0x1b, KEY_MUTE },
39
40 { 0x17, KEY_CHANNELDOWN },
41 { 0x16, KEY_CHANNELUP },
42 { 0x10, KEY_VOLUMEUP },
43 { 0x14, KEY_VOLUMEDOWN },
44 { 0x13, KEY_ZOOM },
45
46 { 0x19, KEY_CAMERA }, /* SNAPSHOT */
47 { 0x1a, KEY_SEARCH }, /* scan */
48
49 { 0x37, KEY_REWIND }, /* << */
50 { 0x32, KEY_RECORD }, /* o (red) */
51 { 0x33, KEY_FORWARD }, /* >> */
52 { 0x11, KEY_STOP }, /* square */
53 { 0x3b, KEY_PLAY }, /* > */
54 { 0x30, KEY_PLAYPAUSE }, /* || */
55
56 { 0x31, KEY_TV },
57 { 0x34, KEY_RADIO },
58};
59
60static struct rc_map_list pixelview_new_map = {
61 .map = {
62 .scan = pixelview_new,
63 .size = ARRAY_SIZE(pixelview_new),
64 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
65 .name = RC_MAP_PIXELVIEW_NEW,
66 }
67};
68
69static int __init init_rc_map_pixelview_new(void)
70{
71 return rc_map_register(&pixelview_new_map);
72}
73
74static void __exit exit_rc_map_pixelview_new(void)
75{
76 rc_map_unregister(&pixelview_new_map);
77}
78
79module_init(init_rc_map_pixelview_new)
80module_exit(exit_rc_map_pixelview_new)
81
82MODULE_LICENSE("GPL");
83MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c
new file mode 100644
index 000000000000..0ec5988916b9
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pixelview.c
@@ -0,0 +1,82 @@
1/* pixelview.h - Keytable for pixelview Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table pixelview[] = {
16
17 { 0x1e, KEY_POWER }, /* power */
18 { 0x07, KEY_MEDIA }, /* source */
19 { 0x1c, KEY_SEARCH }, /* scan */
20
21
22 { 0x03, KEY_TUNER }, /* TV/FM */
23
24 { 0x00, KEY_RECORD },
25 { 0x08, KEY_STOP },
26 { 0x11, KEY_PLAY },
27
28 { 0x1a, KEY_PLAYPAUSE }, /* freeze */
29 { 0x19, KEY_ZOOM }, /* zoom */
30 { 0x0f, KEY_TEXT }, /* min */
31
32 { 0x01, KEY_1 },
33 { 0x0b, KEY_2 },
34 { 0x1b, KEY_3 },
35 { 0x05, KEY_4 },
36 { 0x09, KEY_5 },
37 { 0x15, KEY_6 },
38 { 0x06, KEY_7 },
39 { 0x0a, KEY_8 },
40 { 0x12, KEY_9 },
41 { 0x02, KEY_0 },
42 { 0x10, KEY_LAST }, /* +100 */
43 { 0x13, KEY_LIST }, /* recall */
44
45 { 0x1f, KEY_CHANNELUP }, /* chn down */
46 { 0x17, KEY_CHANNELDOWN }, /* chn up */
47 { 0x16, KEY_VOLUMEUP }, /* vol down */
48 { 0x14, KEY_VOLUMEDOWN }, /* vol up */
49
50 { 0x04, KEY_KPMINUS }, /* <<< */
51 { 0x0e, KEY_SETUP }, /* function */
52 { 0x0c, KEY_KPPLUS }, /* >>> */
53
54 { 0x0d, KEY_GOTO }, /* mts */
55 { 0x1d, KEY_REFRESH }, /* reset */
56 { 0x18, KEY_MUTE }, /* mute/unmute */
57};
58
59static struct rc_map_list pixelview_map = {
60 .map = {
61 .scan = pixelview,
62 .size = ARRAY_SIZE(pixelview),
63 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
64 .name = RC_MAP_PIXELVIEW,
65 }
66};
67
68static int __init init_rc_map_pixelview(void)
69{
70 return rc_map_register(&pixelview_map);
71}
72
73static void __exit exit_rc_map_pixelview(void)
74{
75 rc_map_unregister(&pixelview_map);
76}
77
78module_init(init_rc_map_pixelview)
79module_exit(exit_rc_map_pixelview)
80
81MODULE_LICENSE("GPL");
82MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
new file mode 100644
index 000000000000..5f9d546a86c4
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
@@ -0,0 +1,81 @@
1/* powercolor-real-angel.h - Keytable for powercolor_real_angel Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 * Remote control for Powercolor Real Angel 330
17 * Daniel Fraga <fragabr@gmail.com>
18 */
19
20static struct rc_map_table powercolor_real_angel[] = {
21 { 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */
22 { 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */
23 { 0x00, KEY_0 },
24 { 0x01, KEY_1 },
25 { 0x02, KEY_2 },
26 { 0x03, KEY_3 },
27 { 0x04, KEY_4 },
28 { 0x05, KEY_5 },
29 { 0x06, KEY_6 },
30 { 0x07, KEY_7 },
31 { 0x08, KEY_8 },
32 { 0x09, KEY_9 },
33 { 0x0a, KEY_DIGITS }, /* single, double, tripple digit */
34 { 0x29, KEY_PREVIOUS }, /* previous channel */
35 { 0x12, KEY_BRIGHTNESSUP },
36 { 0x13, KEY_BRIGHTNESSDOWN },
37 { 0x2b, KEY_MODE }, /* stereo/mono */
38 { 0x2c, KEY_TEXT }, /* teletext */
39 { 0x20, KEY_CHANNELUP }, /* channel up */
40 { 0x21, KEY_CHANNELDOWN }, /* channel down */
41 { 0x10, KEY_VOLUMEUP }, /* volume up */
42 { 0x11, KEY_VOLUMEDOWN }, /* volume down */
43 { 0x0d, KEY_MUTE },
44 { 0x1f, KEY_RECORD },
45 { 0x17, KEY_PLAY },
46 { 0x16, KEY_PAUSE },
47 { 0x0b, KEY_STOP },
48 { 0x27, KEY_FASTFORWARD },
49 { 0x26, KEY_REWIND },
50 { 0x1e, KEY_SEARCH }, /* autoscan */
51 { 0x0e, KEY_CAMERA }, /* snapshot */
52 { 0x2d, KEY_SETUP },
53 { 0x0f, KEY_SCREEN }, /* full screen */
54 { 0x14, KEY_RADIO }, /* FM radio */
55 { 0x25, KEY_POWER }, /* power */
56};
57
58static struct rc_map_list powercolor_real_angel_map = {
59 .map = {
60 .scan = powercolor_real_angel,
61 .size = ARRAY_SIZE(powercolor_real_angel),
62 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
63 .name = RC_MAP_POWERCOLOR_REAL_ANGEL,
64 }
65};
66
67static int __init init_rc_map_powercolor_real_angel(void)
68{
69 return rc_map_register(&powercolor_real_angel_map);
70}
71
72static void __exit exit_rc_map_powercolor_real_angel(void)
73{
74 rc_map_unregister(&powercolor_real_angel_map);
75}
76
77module_init(init_rc_map_powercolor_real_angel)
78module_exit(exit_rc_map_powercolor_real_angel)
79
80MODULE_LICENSE("GPL");
81MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c
new file mode 100644
index 000000000000..8a3a643879d4
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-proteus-2309.c
@@ -0,0 +1,69 @@
1/* proteus-2309.h - Keytable for proteus_2309 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
16
17static struct rc_map_table proteus_2309[] = {
18 /* numeric */
19 { 0x00, KEY_0 },
20 { 0x01, KEY_1 },
21 { 0x02, KEY_2 },
22 { 0x03, KEY_3 },
23 { 0x04, KEY_4 },
24 { 0x05, KEY_5 },
25 { 0x06, KEY_6 },
26 { 0x07, KEY_7 },
27 { 0x08, KEY_8 },
28 { 0x09, KEY_9 },
29
30 { 0x5c, KEY_POWER }, /* power */
31 { 0x20, KEY_ZOOM }, /* full screen */
32 { 0x0f, KEY_BACKSPACE }, /* recall */
33 { 0x1b, KEY_ENTER }, /* mute */
34 { 0x41, KEY_RECORD }, /* record */
35 { 0x43, KEY_STOP }, /* stop */
36 { 0x16, KEY_S },
37 { 0x1a, KEY_POWER2 }, /* off */
38 { 0x2e, KEY_RED },
39 { 0x1f, KEY_CHANNELDOWN }, /* channel - */
40 { 0x1c, KEY_CHANNELUP }, /* channel + */
41 { 0x10, KEY_VOLUMEDOWN }, /* volume - */
42 { 0x1e, KEY_VOLUMEUP }, /* volume + */
43 { 0x14, KEY_F1 },
44};
45
46static struct rc_map_list proteus_2309_map = {
47 .map = {
48 .scan = proteus_2309,
49 .size = ARRAY_SIZE(proteus_2309),
50 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
51 .name = RC_MAP_PROTEUS_2309,
52 }
53};
54
55static int __init init_rc_map_proteus_2309(void)
56{
57 return rc_map_register(&proteus_2309_map);
58}
59
60static void __exit exit_rc_map_proteus_2309(void)
61{
62 rc_map_unregister(&proteus_2309_map);
63}
64
65module_init(init_rc_map_proteus_2309)
66module_exit(exit_rc_map_proteus_2309)
67
68MODULE_LICENSE("GPL");
69MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c
new file mode 100644
index 000000000000..ef90296bfd68
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-purpletv.c
@@ -0,0 +1,81 @@
1/* purpletv.h - Keytable for purpletv Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table purpletv[] = {
16 { 0x03, KEY_POWER },
17 { 0x6f, KEY_MUTE },
18 { 0x10, KEY_BACKSPACE }, /* Recall */
19
20 { 0x11, KEY_0 },
21 { 0x04, KEY_1 },
22 { 0x05, KEY_2 },
23 { 0x06, KEY_3 },
24 { 0x08, KEY_4 },
25 { 0x09, KEY_5 },
26 { 0x0a, KEY_6 },
27 { 0x0c, KEY_7 },
28 { 0x0d, KEY_8 },
29 { 0x0e, KEY_9 },
30 { 0x12, KEY_DOT }, /* 100+ */
31
32 { 0x07, KEY_VOLUMEUP },
33 { 0x0b, KEY_VOLUMEDOWN },
34 { 0x1a, KEY_KPPLUS },
35 { 0x18, KEY_KPMINUS },
36 { 0x15, KEY_UP },
37 { 0x1d, KEY_DOWN },
38 { 0x0f, KEY_CHANNELUP },
39 { 0x13, KEY_CHANNELDOWN },
40 { 0x48, KEY_ZOOM },
41
42 { 0x1b, KEY_VIDEO }, /* Video source */
43 { 0x1f, KEY_CAMERA }, /* Snapshot */
44 { 0x49, KEY_LANGUAGE }, /* MTS Select */
45 { 0x19, KEY_SEARCH }, /* Auto Scan */
46
47 { 0x4b, KEY_RECORD },
48 { 0x46, KEY_PLAY },
49 { 0x45, KEY_PAUSE }, /* Pause */
50 { 0x44, KEY_STOP },
51 { 0x43, KEY_TIME }, /* Time Shift */
52 { 0x17, KEY_CHANNEL }, /* SURF CH */
53 { 0x40, KEY_FORWARD }, /* Forward ? */
54 { 0x42, KEY_REWIND }, /* Backward ? */
55
56};
57
58static struct rc_map_list purpletv_map = {
59 .map = {
60 .scan = purpletv,
61 .size = ARRAY_SIZE(purpletv),
62 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
63 .name = RC_MAP_PURPLETV,
64 }
65};
66
67static int __init init_rc_map_purpletv(void)
68{
69 return rc_map_register(&purpletv_map);
70}
71
72static void __exit exit_rc_map_purpletv(void)
73{
74 rc_map_unregister(&purpletv_map);
75}
76
77module_init(init_rc_map_purpletv)
78module_exit(exit_rc_map_purpletv)
79
80MODULE_LICENSE("GPL");
81MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c
new file mode 100644
index 000000000000..83a418de12c6
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pv951.c
@@ -0,0 +1,78 @@
1/* pv951.h - Keytable for pv951 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Mark Phalan <phalanm@o2.ie> */
16
17static struct rc_map_table pv951[] = {
18 { 0x00, KEY_0 },
19 { 0x01, KEY_1 },
20 { 0x02, KEY_2 },
21 { 0x03, KEY_3 },
22 { 0x04, KEY_4 },
23 { 0x05, KEY_5 },
24 { 0x06, KEY_6 },
25 { 0x07, KEY_7 },
26 { 0x08, KEY_8 },
27 { 0x09, KEY_9 },
28
29 { 0x12, KEY_POWER },
30 { 0x10, KEY_MUTE },
31 { 0x1f, KEY_VOLUMEDOWN },
32 { 0x1b, KEY_VOLUMEUP },
33 { 0x1a, KEY_CHANNELUP },
34 { 0x1e, KEY_CHANNELDOWN },
35 { 0x0e, KEY_PAGEUP },
36 { 0x1d, KEY_PAGEDOWN },
37 { 0x13, KEY_SOUND },
38
39 { 0x18, KEY_KPPLUSMINUS }, /* CH +/- */
40 { 0x16, KEY_SUBTITLE }, /* CC */
41 { 0x0d, KEY_TEXT }, /* TTX */
42 { 0x0b, KEY_TV }, /* AIR/CBL */
43 { 0x11, KEY_PC }, /* PC/TV */
44 { 0x17, KEY_OK }, /* CH RTN */
45 { 0x19, KEY_MODE }, /* FUNC */
46 { 0x0c, KEY_SEARCH }, /* AUTOSCAN */
47
48 /* Not sure what to do with these ones! */
49 { 0x0f, KEY_SELECT }, /* SOURCE */
50 { 0x0a, KEY_KPPLUS }, /* +100 */
51 { 0x14, KEY_EQUAL }, /* SYNC */
52 { 0x1c, KEY_MEDIA }, /* PC/TV */
53};
54
55static struct rc_map_list pv951_map = {
56 .map = {
57 .scan = pv951,
58 .size = ARRAY_SIZE(pv951),
59 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
60 .name = RC_MAP_PV951,
61 }
62};
63
64static int __init init_rc_map_pv951(void)
65{
66 return rc_map_register(&pv951_map);
67}
68
69static void __exit exit_rc_map_pv951(void)
70{
71 rc_map_unregister(&pv951_map);
72}
73
74module_init(init_rc_map_pv951)
75module_exit(exit_rc_map_pv951)
76
77MODULE_LICENSE("GPL");
78MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c
new file mode 100644
index 000000000000..dfc9b15f43a9
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c
@@ -0,0 +1,141 @@
1/* rc5-hauppauge-new.h - Keytable for rc5_hauppauge_new Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/*
16 * Hauppauge:the newer, gray remotes (seems there are multiple
17 * slightly different versions), shipped with cx88+ivtv cards.
18 *
19 * This table contains the complete RC5 code, instead of just the data part
20 */
21
22static struct rc_map_table rc5_hauppauge_new[] = {
23 /* Keys 0 to 9 */
24 { 0x1e00, KEY_0 },
25 { 0x1e01, KEY_1 },
26 { 0x1e02, KEY_2 },
27 { 0x1e03, KEY_3 },
28 { 0x1e04, KEY_4 },
29 { 0x1e05, KEY_5 },
30 { 0x1e06, KEY_6 },
31 { 0x1e07, KEY_7 },
32 { 0x1e08, KEY_8 },
33 { 0x1e09, KEY_9 },
34
35 { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */
36 { 0x1e0b, KEY_RED }, /* red button */
37 { 0x1e0c, KEY_RADIO },
38 { 0x1e0d, KEY_MENU },
39 { 0x1e0e, KEY_SUBTITLE }, /* also the # key */
40 { 0x1e0f, KEY_MUTE },
41 { 0x1e10, KEY_VOLUMEUP },
42 { 0x1e11, KEY_VOLUMEDOWN },
43 { 0x1e12, KEY_PREVIOUS }, /* previous channel */
44 { 0x1e14, KEY_UP },
45 { 0x1e15, KEY_DOWN },
46 { 0x1e16, KEY_LEFT },
47 { 0x1e17, KEY_RIGHT },
48 { 0x1e18, KEY_VIDEO }, /* Videos */
49 { 0x1e19, KEY_AUDIO }, /* Music */
50 /* 0x1e1a: Pictures - presume this means
51 "Multimedia Home Platform" -
52 no "PICTURES" key in input.h
53 */
54 { 0x1e1a, KEY_MHP },
55
56 { 0x1e1b, KEY_EPG }, /* Guide */
57 { 0x1e1c, KEY_TV },
58 { 0x1e1e, KEY_NEXTSONG }, /* skip >| */
59 { 0x1e1f, KEY_EXIT }, /* back/exit */
60 { 0x1e20, KEY_CHANNELUP }, /* channel / program + */
61 { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */
62 { 0x1e22, KEY_CHANNEL }, /* source (old black remote) */
63 { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */
64 { 0x1e25, KEY_ENTER }, /* OK */
65 { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */
66 { 0x1e29, KEY_BLUE }, /* blue key */
67 { 0x1e2e, KEY_GREEN }, /* green button */
68 { 0x1e30, KEY_PAUSE }, /* pause */
69 { 0x1e32, KEY_REWIND }, /* backward << */
70 { 0x1e34, KEY_FASTFORWARD }, /* forward >> */
71 { 0x1e35, KEY_PLAY },
72 { 0x1e36, KEY_STOP },
73 { 0x1e37, KEY_RECORD }, /* recording */
74 { 0x1e38, KEY_YELLOW }, /* yellow key */
75 { 0x1e3b, KEY_SELECT }, /* top right button */
76 { 0x1e3c, KEY_ZOOM }, /* full */
77 { 0x1e3d, KEY_POWER }, /* system power (green button) */
78
79 /* Keycodes for DSR-0112 remote bundled with Haupauge MiniStick */
80 { 0x1d00, KEY_0 },
81 { 0x1d01, KEY_1 },
82 { 0x1d02, KEY_2 },
83 { 0x1d03, KEY_3 },
84 { 0x1d04, KEY_4 },
85 { 0x1d05, KEY_5 },
86 { 0x1d06, KEY_6 },
87 { 0x1d07, KEY_7 },
88 { 0x1d08, KEY_8 },
89 { 0x1d09, KEY_9 },
90 { 0x1d0a, KEY_TEXT },
91 { 0x1d0d, KEY_MENU },
92 { 0x1d0f, KEY_MUTE },
93 { 0x1d10, KEY_VOLUMEUP },
94 { 0x1d11, KEY_VOLUMEDOWN },
95 { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */
96 { 0x1d14, KEY_UP },
97 { 0x1d15, KEY_DOWN },
98 { 0x1d16, KEY_LEFT },
99 { 0x1d17, KEY_RIGHT },
100 { 0x1d1c, KEY_TV },
101 { 0x1d1e, KEY_NEXT }, /* >| */
102 { 0x1d1f, KEY_EXIT },
103 { 0x1d20, KEY_CHANNELUP },
104 { 0x1d21, KEY_CHANNELDOWN },
105 { 0x1d24, KEY_LAST }, /* <| */
106 { 0x1d25, KEY_OK },
107 { 0x1d30, KEY_PAUSE },
108 { 0x1d32, KEY_REWIND },
109 { 0x1d34, KEY_FASTFORWARD },
110 { 0x1d35, KEY_PLAY },
111 { 0x1d36, KEY_STOP },
112 { 0x1d37, KEY_RECORD },
113 { 0x1d3b, KEY_GOTO },
114 { 0x1d3d, KEY_POWER },
115 { 0x1d3f, KEY_HOME },
116};
117
118static struct rc_map_list rc5_hauppauge_new_map = {
119 .map = {
120 .scan = rc5_hauppauge_new,
121 .size = ARRAY_SIZE(rc5_hauppauge_new),
122 .rc_type = RC_TYPE_RC5,
123 .name = RC_MAP_RC5_HAUPPAUGE_NEW,
124 }
125};
126
127static int __init init_rc_map_rc5_hauppauge_new(void)
128{
129 return rc_map_register(&rc5_hauppauge_new_map);
130}
131
132static void __exit exit_rc_map_rc5_hauppauge_new(void)
133{
134 rc_map_unregister(&rc5_hauppauge_new_map);
135}
136
137module_init(init_rc_map_rc5_hauppauge_new)
138module_exit(exit_rc_map_rc5_hauppauge_new)
139
140MODULE_LICENSE("GPL");
141MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-rc5-tv.c b/drivers/media/rc/keymaps/rc-rc5-tv.c
new file mode 100644
index 000000000000..4fcef9f1f721
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-rc5-tv.c
@@ -0,0 +1,81 @@
1/* rc5-tv.h - Keytable for rc5_tv Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* generic RC5 keytable */
16/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
17/* used by old (black) Hauppauge remotes */
18
19static struct rc_map_table rc5_tv[] = {
20 /* Keys 0 to 9 */
21 { 0x00, KEY_0 },
22 { 0x01, KEY_1 },
23 { 0x02, KEY_2 },
24 { 0x03, KEY_3 },
25 { 0x04, KEY_4 },
26 { 0x05, KEY_5 },
27 { 0x06, KEY_6 },
28 { 0x07, KEY_7 },
29 { 0x08, KEY_8 },
30 { 0x09, KEY_9 },
31
32 { 0x0b, KEY_CHANNEL }, /* channel / program (japan: 11) */
33 { 0x0c, KEY_POWER }, /* standby */
34 { 0x0d, KEY_MUTE }, /* mute / demute */
35 { 0x0f, KEY_TV }, /* display */
36 { 0x10, KEY_VOLUMEUP },
37 { 0x11, KEY_VOLUMEDOWN },
38 { 0x12, KEY_BRIGHTNESSUP },
39 { 0x13, KEY_BRIGHTNESSDOWN },
40 { 0x1e, KEY_SEARCH }, /* search + */
41 { 0x20, KEY_CHANNELUP }, /* channel / program + */
42 { 0x21, KEY_CHANNELDOWN }, /* channel / program - */
43 { 0x22, KEY_CHANNEL }, /* alt / channel */
44 { 0x23, KEY_LANGUAGE }, /* 1st / 2nd language */
45 { 0x26, KEY_SLEEP }, /* sleeptimer */
46 { 0x2e, KEY_MENU }, /* 2nd controls (USA: menu) */
47 { 0x30, KEY_PAUSE },
48 { 0x32, KEY_REWIND },
49 { 0x33, KEY_GOTO },
50 { 0x35, KEY_PLAY },
51 { 0x36, KEY_STOP },
52 { 0x37, KEY_RECORD }, /* recording */
53 { 0x3c, KEY_TEXT }, /* teletext submode (Japan: 12) */
54 { 0x3d, KEY_SUSPEND }, /* system standby */
55
56};
57
58static struct rc_map_list rc5_tv_map = {
59 .map = {
60 .scan = rc5_tv,
61 .size = ARRAY_SIZE(rc5_tv),
62 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
63 .name = RC_MAP_RC5_TV,
64 }
65};
66
67static int __init init_rc_map_rc5_tv(void)
68{
69 return rc_map_register(&rc5_tv_map);
70}
71
72static void __exit exit_rc_map_rc5_tv(void)
73{
74 rc_map_unregister(&rc5_tv_map);
75}
76
77module_init(init_rc_map_rc5_tv)
78module_exit(exit_rc_map_rc5_tv)
79
80MODULE_LICENSE("GPL");
81MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c
new file mode 100644
index 000000000000..3bf3337875d1
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-rc6-mce.c
@@ -0,0 +1,113 @@
1/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use
2 * with the Media Center Edition eHome Infrared Transceiver.
3 *
4 * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-map.h>
13
14static struct rc_map_table rc6_mce[] = {
15
16 { 0x800f0400, KEY_NUMERIC_0 },
17 { 0x800f0401, KEY_NUMERIC_1 },
18 { 0x800f0402, KEY_NUMERIC_2 },
19 { 0x800f0403, KEY_NUMERIC_3 },
20 { 0x800f0404, KEY_NUMERIC_4 },
21 { 0x800f0405, KEY_NUMERIC_5 },
22 { 0x800f0406, KEY_NUMERIC_6 },
23 { 0x800f0407, KEY_NUMERIC_7 },
24 { 0x800f0408, KEY_NUMERIC_8 },
25 { 0x800f0409, KEY_NUMERIC_9 },
26
27 { 0x800f040a, KEY_DELETE },
28 { 0x800f040b, KEY_ENTER },
29 { 0x800f040c, KEY_POWER }, /* PC Power */
30 { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
31 { 0x800f040e, KEY_MUTE },
32 { 0x800f040f, KEY_INFO },
33
34 { 0x800f0410, KEY_VOLUMEUP },
35 { 0x800f0411, KEY_VOLUMEDOWN },
36 { 0x800f0412, KEY_CHANNELUP },
37 { 0x800f0413, KEY_CHANNELDOWN },
38
39 { 0x800f0414, KEY_FASTFORWARD },
40 { 0x800f0415, KEY_REWIND },
41 { 0x800f0416, KEY_PLAY },
42 { 0x800f0417, KEY_RECORD },
43 { 0x800f0418, KEY_PAUSE },
44 { 0x800f046e, KEY_PLAYPAUSE },
45 { 0x800f0419, KEY_STOP },
46 { 0x800f041a, KEY_NEXT },
47 { 0x800f041b, KEY_PREVIOUS },
48 { 0x800f041c, KEY_NUMERIC_POUND },
49 { 0x800f041d, KEY_NUMERIC_STAR },
50
51 { 0x800f041e, KEY_UP },
52 { 0x800f041f, KEY_DOWN },
53 { 0x800f0420, KEY_LEFT },
54 { 0x800f0421, KEY_RIGHT },
55
56 { 0x800f0422, KEY_OK },
57 { 0x800f0423, KEY_EXIT },
58 { 0x800f0424, KEY_DVD },
59 { 0x800f0425, KEY_TUNER }, /* LiveTV */
60 { 0x800f0426, KEY_EPG }, /* Guide */
61 { 0x800f0427, KEY_ZOOM }, /* Aspect */
62
63 { 0x800f043a, KEY_BRIGHTNESSUP },
64
65 { 0x800f0446, KEY_TV },
66 { 0x800f0447, KEY_AUDIO }, /* My Music */
67 { 0x800f0448, KEY_PVR }, /* RecordedTV */
68 { 0x800f0449, KEY_CAMERA },
69 { 0x800f044a, KEY_VIDEO },
70 { 0x800f044c, KEY_LANGUAGE },
71 { 0x800f044d, KEY_TITLE },
72 { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
73
74 { 0x800f0450, KEY_RADIO },
75
76 { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
77 { 0x800f045b, KEY_RED },
78 { 0x800f045c, KEY_GREEN },
79 { 0x800f045d, KEY_YELLOW },
80 { 0x800f045e, KEY_BLUE },
81
82 { 0x800f0465, KEY_POWER2 }, /* TV Power */
83 { 0x800f046e, KEY_PLAYPAUSE },
84 { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
85
86 { 0x800f0480, KEY_BRIGHTNESSDOWN },
87 { 0x800f0481, KEY_PLAYPAUSE },
88};
89
90static struct rc_map_list rc6_mce_map = {
91 .map = {
92 .scan = rc6_mce,
93 .size = ARRAY_SIZE(rc6_mce),
94 .rc_type = RC_TYPE_RC6,
95 .name = RC_MAP_RC6_MCE,
96 }
97};
98
99static int __init init_rc_map_rc6_mce(void)
100{
101 return rc_map_register(&rc6_mce_map);
102}
103
104static void __exit exit_rc_map_rc6_mce(void)
105{
106 rc_map_unregister(&rc6_mce_map);
107}
108
109module_init(init_rc_map_rc6_mce)
110module_exit(exit_rc_map_rc6_mce)
111
112MODULE_LICENSE("GPL");
113MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
new file mode 100644
index 000000000000..2d14598592d8
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
@@ -0,0 +1,78 @@
1/* real-audio-220-32-keys.h - Keytable for real_audio_220_32_keys Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Zogis Real Audio 220 - 32 keys IR */
16
17static struct rc_map_table real_audio_220_32_keys[] = {
18 { 0x1c, KEY_RADIO},
19 { 0x12, KEY_POWER2},
20
21 { 0x01, KEY_1},
22 { 0x02, KEY_2},
23 { 0x03, KEY_3},
24 { 0x04, KEY_4},
25 { 0x05, KEY_5},
26 { 0x06, KEY_6},
27 { 0x07, KEY_7},
28 { 0x08, KEY_8},
29 { 0x09, KEY_9},
30 { 0x00, KEY_0},
31
32 { 0x0c, KEY_VOLUMEUP},
33 { 0x18, KEY_VOLUMEDOWN},
34 { 0x0b, KEY_CHANNELUP},
35 { 0x15, KEY_CHANNELDOWN},
36 { 0x16, KEY_ENTER},
37
38 { 0x11, KEY_LIST}, /* Source */
39 { 0x0d, KEY_AUDIO}, /* stereo */
40
41 { 0x0f, KEY_PREVIOUS}, /* Prev */
42 { 0x1b, KEY_TIME}, /* Timeshift */
43 { 0x1a, KEY_NEXT}, /* Next */
44
45 { 0x0e, KEY_STOP},
46 { 0x1f, KEY_PLAY},
47 { 0x1e, KEY_PLAYPAUSE}, /* Pause */
48
49 { 0x1d, KEY_RECORD},
50 { 0x13, KEY_MUTE},
51 { 0x19, KEY_CAMERA}, /* Snapshot */
52
53};
54
55static struct rc_map_list real_audio_220_32_keys_map = {
56 .map = {
57 .scan = real_audio_220_32_keys,
58 .size = ARRAY_SIZE(real_audio_220_32_keys),
59 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
60 .name = RC_MAP_REAL_AUDIO_220_32_KEYS,
61 }
62};
63
64static int __init init_rc_map_real_audio_220_32_keys(void)
65{
66 return rc_map_register(&real_audio_220_32_keys_map);
67}
68
69static void __exit exit_rc_map_real_audio_220_32_keys(void)
70{
71 rc_map_unregister(&real_audio_220_32_keys_map);
72}
73
74module_init(init_rc_map_real_audio_220_32_keys)
75module_exit(exit_rc_map_real_audio_220_32_keys)
76
77MODULE_LICENSE("GPL");
78MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c
new file mode 100644
index 000000000000..92cc10d2f9cd
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-streamzap.c
@@ -0,0 +1,82 @@
1/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use
2 * with the Streamzap PC Remote IR Receiver.
3 *
4 * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <media/rc-map.h>
13
14static struct rc_map_table streamzap[] = {
15/*
16 * The Streamzap remote is almost, but not quite, RC-5, as it has an extra
17 * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
18 * an additional RC-5-sz decoder is being deployed to support it, but it
19 * may be possible to merge it back with the standard RC-5 decoder.
20 */
21 { 0x28c0, KEY_NUMERIC_0 },
22 { 0x28c1, KEY_NUMERIC_1 },
23 { 0x28c2, KEY_NUMERIC_2 },
24 { 0x28c3, KEY_NUMERIC_3 },
25 { 0x28c4, KEY_NUMERIC_4 },
26 { 0x28c5, KEY_NUMERIC_5 },
27 { 0x28c6, KEY_NUMERIC_6 },
28 { 0x28c7, KEY_NUMERIC_7 },
29 { 0x28c8, KEY_NUMERIC_8 },
30 { 0x28c9, KEY_NUMERIC_9 },
31 { 0x28ca, KEY_POWER },
32 { 0x28cb, KEY_MUTE },
33 { 0x28cc, KEY_CHANNELUP },
34 { 0x28cd, KEY_VOLUMEUP },
35 { 0x28ce, KEY_CHANNELDOWN },
36 { 0x28cf, KEY_VOLUMEDOWN },
37 { 0x28d0, KEY_UP },
38 { 0x28d1, KEY_LEFT },
39 { 0x28d2, KEY_OK },
40 { 0x28d3, KEY_RIGHT },
41 { 0x28d4, KEY_DOWN },
42 { 0x28d5, KEY_MENU },
43 { 0x28d6, KEY_EXIT },
44 { 0x28d7, KEY_PLAY },
45 { 0x28d8, KEY_PAUSE },
46 { 0x28d9, KEY_STOP },
47 { 0x28da, KEY_BACK },
48 { 0x28db, KEY_FORWARD },
49 { 0x28dc, KEY_RECORD },
50 { 0x28dd, KEY_REWIND },
51 { 0x28de, KEY_FASTFORWARD },
52 { 0x28e0, KEY_RED },
53 { 0x28e1, KEY_GREEN },
54 { 0x28e2, KEY_YELLOW },
55 { 0x28e3, KEY_BLUE },
56
57};
58
59static struct rc_map_list streamzap_map = {
60 .map = {
61 .scan = streamzap,
62 .size = ARRAY_SIZE(streamzap),
63 .rc_type = RC_TYPE_RC5_SZ,
64 .name = RC_MAP_STREAMZAP,
65 }
66};
67
68static int __init init_rc_map_streamzap(void)
69{
70 return rc_map_register(&streamzap_map);
71}
72
73static void __exit exit_rc_map_streamzap(void)
74{
75 rc_map_unregister(&streamzap_map);
76}
77
78module_init(init_rc_map_streamzap)
79module_exit(exit_rc_map_streamzap)
80
81MODULE_LICENSE("GPL");
82MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c
new file mode 100644
index 000000000000..7242ee66f6e0
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tbs-nec.c
@@ -0,0 +1,75 @@
1/* tbs-nec.h - Keytable for tbs_nec Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table tbs_nec[] = {
16 { 0x84, KEY_POWER2}, /* power */
17 { 0x94, KEY_MUTE}, /* mute */
18 { 0x87, KEY_1},
19 { 0x86, KEY_2},
20 { 0x85, KEY_3},
21 { 0x8b, KEY_4},
22 { 0x8a, KEY_5},
23 { 0x89, KEY_6},
24 { 0x8f, KEY_7},
25 { 0x8e, KEY_8},
26 { 0x8d, KEY_9},
27 { 0x92, KEY_0},
28 { 0xc0, KEY_10CHANNELSUP}, /* 10+ */
29 { 0xd0, KEY_10CHANNELSDOWN}, /* 10- */
30 { 0x96, KEY_CHANNELUP}, /* ch+ */
31 { 0x91, KEY_CHANNELDOWN}, /* ch- */
32 { 0x93, KEY_VOLUMEUP}, /* vol+ */
33 { 0x8c, KEY_VOLUMEDOWN}, /* vol- */
34 { 0x83, KEY_RECORD}, /* rec */
35 { 0x98, KEY_PAUSE}, /* pause, yellow */
36 { 0x99, KEY_OK}, /* ok */
37 { 0x9a, KEY_CAMERA}, /* snapshot */
38 { 0x81, KEY_UP},
39 { 0x90, KEY_LEFT},
40 { 0x82, KEY_RIGHT},
41 { 0x88, KEY_DOWN},
42 { 0x95, KEY_FAVORITES}, /* blue */
43 { 0x97, KEY_SUBTITLE}, /* green */
44 { 0x9d, KEY_ZOOM},
45 { 0x9f, KEY_EXIT},
46 { 0x9e, KEY_MENU},
47 { 0x9c, KEY_EPG},
48 { 0x80, KEY_PREVIOUS}, /* red */
49 { 0x9b, KEY_MODE},
50};
51
52static struct rc_map_list tbs_nec_map = {
53 .map = {
54 .scan = tbs_nec,
55 .size = ARRAY_SIZE(tbs_nec),
56 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
57 .name = RC_MAP_TBS_NEC,
58 }
59};
60
61static int __init init_rc_map_tbs_nec(void)
62{
63 return rc_map_register(&tbs_nec_map);
64}
65
66static void __exit exit_rc_map_tbs_nec(void)
67{
68 rc_map_unregister(&tbs_nec_map);
69}
70
71module_init(init_rc_map_tbs_nec)
72module_exit(exit_rc_map_tbs_nec)
73
74MODULE_LICENSE("GPL");
75MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
new file mode 100644
index 000000000000..bc38e34b9fda
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
@@ -0,0 +1,92 @@
1/* terratec-cinergy-xs.h - Keytable for terratec_cinergy_xs Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Terratec Cinergy Hybrid T USB XS
16 Devin Heitmueller <dheitmueller@linuxtv.org>
17 */
18
19static struct rc_map_table terratec_cinergy_xs[] = {
20 { 0x41, KEY_HOME},
21 { 0x01, KEY_POWER},
22 { 0x42, KEY_MENU},
23 { 0x02, KEY_1},
24 { 0x03, KEY_2},
25 { 0x04, KEY_3},
26 { 0x43, KEY_SUBTITLE},
27 { 0x05, KEY_4},
28 { 0x06, KEY_5},
29 { 0x07, KEY_6},
30 { 0x44, KEY_TEXT},
31 { 0x08, KEY_7},
32 { 0x09, KEY_8},
33 { 0x0a, KEY_9},
34 { 0x45, KEY_DELETE},
35 { 0x0b, KEY_TUNER},
36 { 0x0c, KEY_0},
37 { 0x0d, KEY_MODE},
38 { 0x46, KEY_TV},
39 { 0x47, KEY_DVD},
40 { 0x49, KEY_VIDEO},
41 { 0x4b, KEY_AUX},
42 { 0x10, KEY_UP},
43 { 0x11, KEY_LEFT},
44 { 0x12, KEY_OK},
45 { 0x13, KEY_RIGHT},
46 { 0x14, KEY_DOWN},
47 { 0x0f, KEY_EPG},
48 { 0x16, KEY_INFO},
49 { 0x4d, KEY_BACKSPACE},
50 { 0x1c, KEY_VOLUMEUP},
51 { 0x4c, KEY_PLAY},
52 { 0x1b, KEY_CHANNELUP},
53 { 0x1e, KEY_VOLUMEDOWN},
54 { 0x1d, KEY_MUTE},
55 { 0x1f, KEY_CHANNELDOWN},
56 { 0x17, KEY_RED},
57 { 0x18, KEY_GREEN},
58 { 0x19, KEY_YELLOW},
59 { 0x1a, KEY_BLUE},
60 { 0x58, KEY_RECORD},
61 { 0x48, KEY_STOP},
62 { 0x40, KEY_PAUSE},
63 { 0x54, KEY_LAST},
64 { 0x4e, KEY_REWIND},
65 { 0x4f, KEY_FASTFORWARD},
66 { 0x5c, KEY_NEXT},
67};
68
69static struct rc_map_list terratec_cinergy_xs_map = {
70 .map = {
71 .scan = terratec_cinergy_xs,
72 .size = ARRAY_SIZE(terratec_cinergy_xs),
73 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
74 .name = RC_MAP_TERRATEC_CINERGY_XS,
75 }
76};
77
78static int __init init_rc_map_terratec_cinergy_xs(void)
79{
80 return rc_map_register(&terratec_cinergy_xs_map);
81}
82
83static void __exit exit_rc_map_terratec_cinergy_xs(void)
84{
85 rc_map_unregister(&terratec_cinergy_xs_map);
86}
87
88module_init(init_rc_map_terratec_cinergy_xs)
89module_exit(exit_rc_map_terratec_cinergy_xs)
90
91MODULE_LICENSE("GPL");
92MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c
new file mode 100644
index 000000000000..1abafa5fd303
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-terratec-slim.c
@@ -0,0 +1,79 @@
1/*
2 * TerraTec remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23/* TerraTec slim remote, 7 rows, 4 columns. */
24/* Uses NEC extended 0x02bd. */
25static struct rc_map_table terratec_slim[] = {
26 { 0x02bd00, KEY_1 },
27 { 0x02bd01, KEY_2 },
28 { 0x02bd02, KEY_3 },
29 { 0x02bd03, KEY_4 },
30 { 0x02bd04, KEY_5 },
31 { 0x02bd05, KEY_6 },
32 { 0x02bd06, KEY_7 },
33 { 0x02bd07, KEY_8 },
34 { 0x02bd08, KEY_9 },
35 { 0x02bd09, KEY_0 },
36 { 0x02bd0a, KEY_MUTE },
37 { 0x02bd0b, KEY_NEW }, /* symbol: PIP */
38 { 0x02bd0e, KEY_VOLUMEDOWN },
39 { 0x02bd0f, KEY_PLAYPAUSE },
40 { 0x02bd10, KEY_RIGHT },
41 { 0x02bd11, KEY_LEFT },
42 { 0x02bd12, KEY_UP },
43 { 0x02bd13, KEY_DOWN },
44 { 0x02bd15, KEY_OK },
45 { 0x02bd16, KEY_STOP },
46 { 0x02bd17, KEY_CAMERA }, /* snapshot */
47 { 0x02bd18, KEY_CHANNELUP },
48 { 0x02bd19, KEY_RECORD },
49 { 0x02bd1a, KEY_CHANNELDOWN },
50 { 0x02bd1c, KEY_ESC },
51 { 0x02bd1f, KEY_VOLUMEUP },
52 { 0x02bd44, KEY_EPG },
53 { 0x02bd45, KEY_POWER2 }, /* [red power button] */
54};
55
56static struct rc_map_list terratec_slim_map = {
57 .map = {
58 .scan = terratec_slim,
59 .size = ARRAY_SIZE(terratec_slim),
60 .rc_type = RC_TYPE_NEC,
61 .name = RC_MAP_TERRATEC_SLIM,
62 }
63};
64
65static int __init init_rc_map_terratec_slim(void)
66{
67 return rc_map_register(&terratec_slim_map);
68}
69
70static void __exit exit_rc_map_terratec_slim(void)
71{
72 rc_map_unregister(&terratec_slim_map);
73}
74
75module_init(init_rc_map_terratec_slim)
76module_exit(exit_rc_map_terratec_slim)
77
78MODULE_LICENSE("GPL");
79MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c
new file mode 100644
index 000000000000..ef5ba3f32735
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tevii-nec.c
@@ -0,0 +1,88 @@
1/* tevii-nec.h - Keytable for tevii_nec Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table tevii_nec[] = {
16 { 0x0a, KEY_POWER2},
17 { 0x0c, KEY_MUTE},
18 { 0x11, KEY_1},
19 { 0x12, KEY_2},
20 { 0x13, KEY_3},
21 { 0x14, KEY_4},
22 { 0x15, KEY_5},
23 { 0x16, KEY_6},
24 { 0x17, KEY_7},
25 { 0x18, KEY_8},
26 { 0x19, KEY_9},
27 { 0x10, KEY_0},
28 { 0x1c, KEY_MENU},
29 { 0x0f, KEY_VOLUMEDOWN},
30 { 0x1a, KEY_LAST},
31 { 0x0e, KEY_OPEN},
32 { 0x04, KEY_RECORD},
33 { 0x09, KEY_VOLUMEUP},
34 { 0x08, KEY_CHANNELUP},
35 { 0x07, KEY_PVR},
36 { 0x0b, KEY_TIME},
37 { 0x02, KEY_RIGHT},
38 { 0x03, KEY_LEFT},
39 { 0x00, KEY_UP},
40 { 0x1f, KEY_OK},
41 { 0x01, KEY_DOWN},
42 { 0x05, KEY_TUNER},
43 { 0x06, KEY_CHANNELDOWN},
44 { 0x40, KEY_PLAYPAUSE},
45 { 0x1e, KEY_REWIND},
46 { 0x1b, KEY_FAVORITES},
47 { 0x1d, KEY_BACK},
48 { 0x4d, KEY_FASTFORWARD},
49 { 0x44, KEY_EPG},
50 { 0x4c, KEY_INFO},
51 { 0x41, KEY_AB},
52 { 0x43, KEY_AUDIO},
53 { 0x45, KEY_SUBTITLE},
54 { 0x4a, KEY_LIST},
55 { 0x46, KEY_F1},
56 { 0x47, KEY_F2},
57 { 0x5e, KEY_F3},
58 { 0x5c, KEY_F4},
59 { 0x52, KEY_F5},
60 { 0x5a, KEY_F6},
61 { 0x56, KEY_MODE},
62 { 0x58, KEY_SWITCHVIDEOMODE},
63};
64
65static struct rc_map_list tevii_nec_map = {
66 .map = {
67 .scan = tevii_nec,
68 .size = ARRAY_SIZE(tevii_nec),
69 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
70 .name = RC_MAP_TEVII_NEC,
71 }
72};
73
74static int __init init_rc_map_tevii_nec(void)
75{
76 return rc_map_register(&tevii_nec_map);
77}
78
79static void __exit exit_rc_map_tevii_nec(void)
80{
81 rc_map_unregister(&tevii_nec_map);
82}
83
84module_init(init_rc_map_tevii_nec)
85module_exit(exit_rc_map_tevii_nec)
86
87MODULE_LICENSE("GPL");
88MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
new file mode 100644
index 000000000000..20ac4e19fb3f
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
@@ -0,0 +1,85 @@
1/*
2 * Total Media In Hand remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23/* Uses NEC extended 0x02bd */
24static struct rc_map_table total_media_in_hand[] = {
25 { 0x02bd00, KEY_1 },
26 { 0x02bd01, KEY_2 },
27 { 0x02bd02, KEY_3 },
28 { 0x02bd03, KEY_4 },
29 { 0x02bd04, KEY_5 },
30 { 0x02bd05, KEY_6 },
31 { 0x02bd06, KEY_7 },
32 { 0x02bd07, KEY_8 },
33 { 0x02bd08, KEY_9 },
34 { 0x02bd09, KEY_0 },
35 { 0x02bd0a, KEY_MUTE },
36 { 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */
37 { 0x02bd0c, KEY_VIDEO }, /* TV / AV */
38 { 0x02bd0e, KEY_VOLUMEDOWN },
39 { 0x02bd0f, KEY_TIME }, /* TimeShift */
40 { 0x02bd10, KEY_RIGHT }, /* right arrow */
41 { 0x02bd11, KEY_LEFT }, /* left arrow */
42 { 0x02bd12, KEY_UP }, /* up arrow */
43 { 0x02bd13, KEY_DOWN }, /* down arrow */
44 { 0x02bd14, KEY_POWER2 }, /* [red] */
45 { 0x02bd15, KEY_OK }, /* OK */
46 { 0x02bd16, KEY_STOP },
47 { 0x02bd17, KEY_CAMERA }, /* Snapshot */
48 { 0x02bd18, KEY_CHANNELUP },
49 { 0x02bd19, KEY_RECORD },
50 { 0x02bd1a, KEY_CHANNELDOWN },
51 { 0x02bd1c, KEY_ESC }, /* Esc */
52 { 0x02bd1e, KEY_PLAY },
53 { 0x02bd1f, KEY_VOLUMEUP },
54 { 0x02bd40, KEY_PAUSE },
55 { 0x02bd41, KEY_FASTFORWARD }, /* FF >> */
56 { 0x02bd42, KEY_REWIND }, /* FR << */
57 { 0x02bd43, KEY_ZOOM }, /* [window + mouse pointer] */
58 { 0x02bd44, KEY_SHUFFLE }, /* Shuffle */
59 { 0x02bd45, KEY_INFO }, /* [red (I)] */
60};
61
62static struct rc_map_list total_media_in_hand_map = {
63 .map = {
64 .scan = total_media_in_hand,
65 .size = ARRAY_SIZE(total_media_in_hand),
66 .rc_type = RC_TYPE_NEC,
67 .name = RC_MAP_TOTAL_MEDIA_IN_HAND,
68 }
69};
70
71static int __init init_rc_map_total_media_in_hand(void)
72{
73 return rc_map_register(&total_media_in_hand_map);
74}
75
76static void __exit exit_rc_map_total_media_in_hand(void)
77{
78 rc_map_unregister(&total_media_in_hand_map);
79}
80
81module_init(init_rc_map_total_media_in_hand)
82module_exit(exit_rc_map_total_media_in_hand)
83
84MODULE_LICENSE("GPL");
85MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c
new file mode 100644
index 000000000000..f8190ead2e32
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-trekstor.c
@@ -0,0 +1,80 @@
1/*
2 * TrekStor remote controller keytable
3 *
4 * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <media/rc-map.h>
22
23/* TrekStor DVB-T USB Stick remote controller. */
24/* Imported from af9015.h.
25 Initial keytable was from Marc Schneider <macke@macke.org> */
26static struct rc_map_table trekstor[] = {
27 { 0x0084, KEY_0 },
28 { 0x0085, KEY_MUTE }, /* Mute */
29 { 0x0086, KEY_HOMEPAGE }, /* Home */
30 { 0x0087, KEY_UP }, /* Up */
31 { 0x0088, KEY_OK }, /* OK */
32 { 0x0089, KEY_RIGHT }, /* Right */
33 { 0x008a, KEY_FASTFORWARD }, /* Fast forward */
34 { 0x008b, KEY_VOLUMEUP }, /* Volume + */
35 { 0x008c, KEY_DOWN }, /* Down */
36 { 0x008d, KEY_PLAY }, /* Play/Pause */
37 { 0x008e, KEY_STOP }, /* Stop */
38 { 0x008f, KEY_EPG }, /* Info/EPG */
39 { 0x0090, KEY_7 },
40 { 0x0091, KEY_4 },
41 { 0x0092, KEY_1 },
42 { 0x0093, KEY_CHANNELDOWN }, /* Channel - */
43 { 0x0094, KEY_8 },
44 { 0x0095, KEY_5 },
45 { 0x0096, KEY_2 },
46 { 0x0097, KEY_CHANNELUP }, /* Channel + */
47 { 0x0098, KEY_9 },
48 { 0x0099, KEY_6 },
49 { 0x009a, KEY_3 },
50 { 0x009b, KEY_VOLUMEDOWN }, /* Volume - */
51 { 0x009c, KEY_TV }, /* TV */
52 { 0x009d, KEY_RECORD }, /* Record */
53 { 0x009e, KEY_REWIND }, /* Rewind */
54 { 0x009f, KEY_LEFT }, /* Left */
55};
56
57static struct rc_map_list trekstor_map = {
58 .map = {
59 .scan = trekstor,
60 .size = ARRAY_SIZE(trekstor),
61 .rc_type = RC_TYPE_NEC,
62 .name = RC_MAP_TREKSTOR,
63 }
64};
65
66static int __init init_rc_map_trekstor(void)
67{
68 return rc_map_register(&trekstor_map);
69}
70
71static void __exit exit_rc_map_trekstor(void)
72{
73 rc_map_unregister(&trekstor_map);
74}
75
76module_init(init_rc_map_trekstor)
77module_exit(exit_rc_map_trekstor)
78
79MODULE_LICENSE("GPL");
80MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c
new file mode 100644
index 000000000000..295f3738e301
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tt-1500.c
@@ -0,0 +1,82 @@
1/* tt-1500.h - Keytable for tt_1500 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* for the Technotrend 1500 bundled remotes (grey and black): */
16
17static struct rc_map_table tt_1500[] = {
18 { 0x1501, KEY_POWER },
19 { 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */
20 { 0x1503, KEY_1 },
21 { 0x1504, KEY_2 },
22 { 0x1505, KEY_3 },
23 { 0x1506, KEY_4 },
24 { 0x1507, KEY_5 },
25 { 0x1508, KEY_6 },
26 { 0x1509, KEY_7 },
27 { 0x150a, KEY_8 },
28 { 0x150b, KEY_9 },
29 { 0x150c, KEY_0 },
30 { 0x150d, KEY_UP },
31 { 0x150e, KEY_LEFT },
32 { 0x150f, KEY_OK },
33 { 0x1510, KEY_RIGHT },
34 { 0x1511, KEY_DOWN },
35 { 0x1512, KEY_INFO },
36 { 0x1513, KEY_EXIT },
37 { 0x1514, KEY_RED },
38 { 0x1515, KEY_GREEN },
39 { 0x1516, KEY_YELLOW },
40 { 0x1517, KEY_BLUE },
41 { 0x1518, KEY_MUTE },
42 { 0x1519, KEY_TEXT },
43 { 0x151a, KEY_MODE }, /* ? TV/Radio */
44 { 0x1521, KEY_OPTION },
45 { 0x1522, KEY_EPG },
46 { 0x1523, KEY_CHANNELUP },
47 { 0x1524, KEY_CHANNELDOWN },
48 { 0x1525, KEY_VOLUMEUP },
49 { 0x1526, KEY_VOLUMEDOWN },
50 { 0x1527, KEY_SETUP },
51 { 0x153a, KEY_RECORD }, /* these keys are only in the black remote */
52 { 0x153b, KEY_PLAY },
53 { 0x153c, KEY_STOP },
54 { 0x153d, KEY_REWIND },
55 { 0x153e, KEY_PAUSE },
56 { 0x153f, KEY_FORWARD },
57};
58
59static struct rc_map_list tt_1500_map = {
60 .map = {
61 .scan = tt_1500,
62 .size = ARRAY_SIZE(tt_1500),
63 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
64 .name = RC_MAP_TT_1500,
65 }
66};
67
68static int __init init_rc_map_tt_1500(void)
69{
70 return rc_map_register(&tt_1500_map);
71}
72
73static void __exit exit_rc_map_tt_1500(void)
74{
75 rc_map_unregister(&tt_1500_map);
76}
77
78module_init(init_rc_map_tt_1500)
79module_exit(exit_rc_map_tt_1500)
80
81MODULE_LICENSE("GPL");
82MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c
new file mode 100644
index 000000000000..8bf8df64b081
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-twinhan1027.c
@@ -0,0 +1,87 @@
1#include <media/rc-map.h>
2
3static struct rc_map_table twinhan_vp1027[] = {
4 { 0x16, KEY_POWER2 },
5 { 0x17, KEY_FAVORITES },
6 { 0x0f, KEY_TEXT },
7 { 0x48, KEY_INFO},
8 { 0x1c, KEY_EPG },
9 { 0x04, KEY_LIST },
10
11 { 0x03, KEY_1 },
12 { 0x01, KEY_2 },
13 { 0x06, KEY_3 },
14 { 0x09, KEY_4 },
15 { 0x1d, KEY_5 },
16 { 0x1f, KEY_6 },
17 { 0x0d, KEY_7 },
18 { 0x19, KEY_8 },
19 { 0x1b, KEY_9 },
20 { 0x15, KEY_0 },
21
22 { 0x0c, KEY_CANCEL },
23 { 0x4a, KEY_CLEAR },
24 { 0x13, KEY_BACKSPACE },
25 { 0x00, KEY_TAB },
26
27 { 0x4b, KEY_UP },
28 { 0x51, KEY_DOWN },
29 { 0x4e, KEY_LEFT },
30 { 0x52, KEY_RIGHT },
31 { 0x4f, KEY_ENTER },
32
33 { 0x1e, KEY_VOLUMEUP },
34 { 0x0a, KEY_VOLUMEDOWN },
35 { 0x02, KEY_CHANNELDOWN },
36 { 0x05, KEY_CHANNELUP },
37 { 0x11, KEY_RECORD },
38
39 { 0x14, KEY_PLAY },
40 { 0x4c, KEY_PAUSE },
41 { 0x1a, KEY_STOP },
42 { 0x40, KEY_REWIND },
43 { 0x12, KEY_FASTFORWARD },
44 { 0x41, KEY_PREVIOUSSONG },
45 { 0x42, KEY_NEXTSONG },
46 { 0x54, KEY_SAVE },
47 { 0x50, KEY_LANGUAGE },
48 { 0x47, KEY_MEDIA },
49 { 0x4d, KEY_SCREEN },
50 { 0x43, KEY_SUBTITLE },
51 { 0x10, KEY_MUTE },
52 { 0x49, KEY_AUDIO },
53 { 0x07, KEY_SLEEP },
54 { 0x08, KEY_VIDEO },
55 { 0x0e, KEY_AGAIN },
56 { 0x45, KEY_EQUAL },
57 { 0x46, KEY_MINUS },
58 { 0x18, KEY_RED },
59 { 0x53, KEY_GREEN },
60 { 0x5e, KEY_YELLOW },
61 { 0x5f, KEY_BLUE },
62};
63
64static struct rc_map_list twinhan_vp1027_map = {
65 .map = {
66 .scan = twinhan_vp1027,
67 .size = ARRAY_SIZE(twinhan_vp1027),
68 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
69 .name = RC_MAP_TWINHAN_VP1027_DVBS,
70 }
71};
72
73static int __init init_rc_map_twinhan_vp1027(void)
74{
75 return rc_map_register(&twinhan_vp1027_map);
76}
77
78static void __exit exit_rc_map_twinhan_vp1027(void)
79{
80 rc_map_unregister(&twinhan_vp1027_map);
81}
82
83module_init(init_rc_map_twinhan_vp1027)
84module_exit(exit_rc_map_twinhan_vp1027)
85
86MODULE_LICENSE("GPL");
87MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>");
diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c
new file mode 100644
index 000000000000..4994d405c0a1
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c
@@ -0,0 +1,92 @@
1/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Pavel Osnova <pvosnova@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table videomate_m1f[] = {
16 { 0x01, KEY_POWER },
17 { 0x31, KEY_TUNER },
18 { 0x33, KEY_VIDEO },
19 { 0x2f, KEY_RADIO },
20 { 0x30, KEY_CAMERA },
21 { 0x2d, KEY_NEW }, /* TV record button */
22 { 0x17, KEY_CYCLEWINDOWS },
23 { 0x2c, KEY_ANGLE },
24 { 0x2b, KEY_LANGUAGE },
25 { 0x32, KEY_SEARCH }, /* '...' button */
26 { 0x11, KEY_UP },
27 { 0x13, KEY_LEFT },
28 { 0x15, KEY_OK },
29 { 0x14, KEY_RIGHT },
30 { 0x12, KEY_DOWN },
31 { 0x16, KEY_BACKSPACE },
32 { 0x02, KEY_ZOOM }, /* WIN key */
33 { 0x04, KEY_INFO },
34 { 0x05, KEY_VOLUMEUP },
35 { 0x03, KEY_MUTE },
36 { 0x07, KEY_CHANNELUP },
37 { 0x06, KEY_VOLUMEDOWN },
38 { 0x08, KEY_CHANNELDOWN },
39 { 0x0c, KEY_RECORD },
40 { 0x0e, KEY_STOP },
41 { 0x0a, KEY_BACK },
42 { 0x0b, KEY_PLAY },
43 { 0x09, KEY_FORWARD },
44 { 0x10, KEY_PREVIOUS },
45 { 0x0d, KEY_PAUSE },
46 { 0x0f, KEY_NEXT },
47 { 0x1e, KEY_1 },
48 { 0x1f, KEY_2 },
49 { 0x20, KEY_3 },
50 { 0x21, KEY_4 },
51 { 0x22, KEY_5 },
52 { 0x23, KEY_6 },
53 { 0x24, KEY_7 },
54 { 0x25, KEY_8 },
55 { 0x26, KEY_9 },
56 { 0x2a, KEY_NUMERIC_STAR }, /* * key */
57 { 0x1d, KEY_0 },
58 { 0x29, KEY_SUBTITLE }, /* # key */
59 { 0x27, KEY_CLEAR },
60 { 0x34, KEY_SCREEN },
61 { 0x28, KEY_ENTER },
62 { 0x19, KEY_RED },
63 { 0x1a, KEY_GREEN },
64 { 0x1b, KEY_YELLOW },
65 { 0x1c, KEY_BLUE },
66 { 0x18, KEY_TEXT },
67};
68
69static struct rc_map_list videomate_m1f_map = {
70 .map = {
71 .scan = videomate_m1f,
72 .size = ARRAY_SIZE(videomate_m1f),
73 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
74 .name = RC_MAP_VIDEOMATE_M1F,
75 }
76};
77
78static int __init init_rc_map_videomate_m1f(void)
79{
80 return rc_map_register(&videomate_m1f_map);
81}
82
83static void __exit exit_rc_map_videomate_m1f(void)
84{
85 rc_map_unregister(&videomate_m1f_map);
86}
87
88module_init(init_rc_map_videomate_m1f)
89module_exit(exit_rc_map_videomate_m1f)
90
91MODULE_LICENSE("GPL");
92MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>");
diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c
new file mode 100644
index 000000000000..9e474a6024e5
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-videomate-s350.c
@@ -0,0 +1,85 @@
1/* videomate-s350.h - Keytable for videomate_s350 Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table videomate_s350[] = {
16 { 0x00, KEY_TV},
17 { 0x01, KEY_DVD},
18 { 0x04, KEY_RECORD},
19 { 0x05, KEY_VIDEO}, /* TV/Video */
20 { 0x07, KEY_STOP},
21 { 0x08, KEY_PLAYPAUSE},
22 { 0x0a, KEY_REWIND},
23 { 0x0f, KEY_FASTFORWARD},
24 { 0x10, KEY_CHANNELUP},
25 { 0x12, KEY_VOLUMEUP},
26 { 0x13, KEY_CHANNELDOWN},
27 { 0x14, KEY_MUTE},
28 { 0x15, KEY_VOLUMEDOWN},
29 { 0x16, KEY_1},
30 { 0x17, KEY_2},
31 { 0x18, KEY_3},
32 { 0x19, KEY_4},
33 { 0x1a, KEY_5},
34 { 0x1b, KEY_6},
35 { 0x1c, KEY_7},
36 { 0x1d, KEY_8},
37 { 0x1e, KEY_9},
38 { 0x1f, KEY_0},
39 { 0x21, KEY_SLEEP},
40 { 0x24, KEY_ZOOM},
41 { 0x25, KEY_LAST}, /* Recall */
42 { 0x26, KEY_SUBTITLE}, /* CC */
43 { 0x27, KEY_LANGUAGE}, /* MTS */
44 { 0x29, KEY_CHANNEL}, /* SURF */
45 { 0x2b, KEY_A},
46 { 0x2c, KEY_B},
47 { 0x2f, KEY_CAMERA}, /* Snapshot */
48 { 0x23, KEY_RADIO},
49 { 0x02, KEY_PREVIOUSSONG},
50 { 0x06, KEY_NEXTSONG},
51 { 0x03, KEY_EPG},
52 { 0x09, KEY_SETUP},
53 { 0x22, KEY_BACKSPACE},
54 { 0x0c, KEY_UP},
55 { 0x0e, KEY_DOWN},
56 { 0x0b, KEY_LEFT},
57 { 0x0d, KEY_RIGHT},
58 { 0x11, KEY_ENTER},
59 { 0x20, KEY_TEXT},
60};
61
62static struct rc_map_list videomate_s350_map = {
63 .map = {
64 .scan = videomate_s350,
65 .size = ARRAY_SIZE(videomate_s350),
66 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
67 .name = RC_MAP_VIDEOMATE_S350,
68 }
69};
70
71static int __init init_rc_map_videomate_s350(void)
72{
73 return rc_map_register(&videomate_s350_map);
74}
75
76static void __exit exit_rc_map_videomate_s350(void)
77{
78 rc_map_unregister(&videomate_s350_map);
79}
80
81module_init(init_rc_map_videomate_s350)
82module_exit(exit_rc_map_videomate_s350)
83
84MODULE_LICENSE("GPL");
85MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
new file mode 100644
index 000000000000..5f2a46e1f8f6
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
@@ -0,0 +1,87 @@
1/* videomate-tv-pvr.h - Keytable for videomate_tv_pvr Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15static struct rc_map_table videomate_tv_pvr[] = {
16 { 0x14, KEY_MUTE },
17 { 0x24, KEY_ZOOM },
18
19 { 0x01, KEY_DVD },
20 { 0x23, KEY_RADIO },
21 { 0x00, KEY_TV },
22
23 { 0x0a, KEY_REWIND },
24 { 0x08, KEY_PLAYPAUSE },
25 { 0x0f, KEY_FORWARD },
26
27 { 0x02, KEY_PREVIOUS },
28 { 0x07, KEY_STOP },
29 { 0x06, KEY_NEXT },
30
31 { 0x0c, KEY_UP },
32 { 0x0e, KEY_DOWN },
33 { 0x0b, KEY_LEFT },
34 { 0x0d, KEY_RIGHT },
35 { 0x11, KEY_OK },
36
37 { 0x03, KEY_MENU },
38 { 0x09, KEY_SETUP },
39 { 0x05, KEY_VIDEO },
40 { 0x22, KEY_CHANNEL },
41
42 { 0x12, KEY_VOLUMEUP },
43 { 0x15, KEY_VOLUMEDOWN },
44 { 0x10, KEY_CHANNELUP },
45 { 0x13, KEY_CHANNELDOWN },
46
47 { 0x04, KEY_RECORD },
48
49 { 0x16, KEY_1 },
50 { 0x17, KEY_2 },
51 { 0x18, KEY_3 },
52 { 0x19, KEY_4 },
53 { 0x1a, KEY_5 },
54 { 0x1b, KEY_6 },
55 { 0x1c, KEY_7 },
56 { 0x1d, KEY_8 },
57 { 0x1e, KEY_9 },
58 { 0x1f, KEY_0 },
59
60 { 0x20, KEY_LANGUAGE },
61 { 0x21, KEY_SLEEP },
62};
63
64static struct rc_map_list videomate_tv_pvr_map = {
65 .map = {
66 .scan = videomate_tv_pvr,
67 .size = ARRAY_SIZE(videomate_tv_pvr),
68 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
69 .name = RC_MAP_VIDEOMATE_TV_PVR,
70 }
71};
72
73static int __init init_rc_map_videomate_tv_pvr(void)
74{
75 return rc_map_register(&videomate_tv_pvr_map);
76}
77
78static void __exit exit_rc_map_videomate_tv_pvr(void)
79{
80 rc_map_unregister(&videomate_tv_pvr_map);
81}
82
83module_init(init_rc_map_videomate_tv_pvr)
84module_exit(exit_rc_map_videomate_tv_pvr)
85
86MODULE_LICENSE("GPL");
87MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
new file mode 100644
index 000000000000..bd8d021f40aa
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
@@ -0,0 +1,82 @@
1/* winfast-usbii-deluxe.h - Keytable for winfast_usbii_deluxe Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Leadtek Winfast TV USB II Deluxe remote
16 Magnus Alm <magnus.alm@gmail.com>
17 */
18
19static struct rc_map_table winfast_usbii_deluxe[] = {
20 { 0x62, KEY_0},
21 { 0x75, KEY_1},
22 { 0x76, KEY_2},
23 { 0x77, KEY_3},
24 { 0x79, KEY_4},
25 { 0x7a, KEY_5},
26 { 0x7b, KEY_6},
27 { 0x7d, KEY_7},
28 { 0x7e, KEY_8},
29 { 0x7f, KEY_9},
30
31 { 0x38, KEY_CAMERA}, /* SNAPSHOT */
32 { 0x37, KEY_RECORD}, /* RECORD */
33 { 0x35, KEY_TIME}, /* TIMESHIFT */
34
35 { 0x74, KEY_VOLUMEUP}, /* VOLUMEUP */
36 { 0x78, KEY_VOLUMEDOWN}, /* VOLUMEDOWN */
37 { 0x64, KEY_MUTE}, /* MUTE */
38
39 { 0x21, KEY_CHANNEL}, /* SURF */
40 { 0x7c, KEY_CHANNELUP}, /* CHANNELUP */
41 { 0x60, KEY_CHANNELDOWN}, /* CHANNELDOWN */
42 { 0x61, KEY_LAST}, /* LAST CHANNEL (RECALL) */
43
44 { 0x72, KEY_VIDEO}, /* INPUT MODES (TV/FM) */
45
46 { 0x70, KEY_POWER2}, /* TV ON/OFF */
47
48 { 0x39, KEY_CYCLEWINDOWS}, /* MINIMIZE (BOSS) */
49 { 0x3a, KEY_NEW}, /* PIP */
50 { 0x73, KEY_ZOOM}, /* FULLSECREEN */
51
52 { 0x66, KEY_INFO}, /* OSD (DISPLAY) */
53
54 { 0x31, KEY_DOT}, /* '.' */
55 { 0x63, KEY_ENTER}, /* ENTER */
56
57};
58
59static struct rc_map_list winfast_usbii_deluxe_map = {
60 .map = {
61 .scan = winfast_usbii_deluxe,
62 .size = ARRAY_SIZE(winfast_usbii_deluxe),
63 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
64 .name = RC_MAP_WINFAST_USBII_DELUXE,
65 }
66};
67
68static int __init init_rc_map_winfast_usbii_deluxe(void)
69{
70 return rc_map_register(&winfast_usbii_deluxe_map);
71}
72
73static void __exit exit_rc_map_winfast_usbii_deluxe(void)
74{
75 rc_map_unregister(&winfast_usbii_deluxe_map);
76}
77
78module_init(init_rc_map_winfast_usbii_deluxe)
79module_exit(exit_rc_map_winfast_usbii_deluxe)
80
81MODULE_LICENSE("GPL");
82MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c
new file mode 100644
index 000000000000..2747db43b70c
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-winfast.c
@@ -0,0 +1,102 @@
1/* winfast.h - Keytable for winfast Remote Controller
2 *
3 * keymap imported from ir-keymaps.c
4 *
5 * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <media/rc-map.h>
14
15/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
16
17static struct rc_map_table winfast[] = {
18 /* Keys 0 to 9 */
19 { 0x12, KEY_0 },
20 { 0x05, KEY_1 },
21 { 0x06, KEY_2 },
22 { 0x07, KEY_3 },
23 { 0x09, KEY_4 },
24 { 0x0a, KEY_5 },
25 { 0x0b, KEY_6 },
26 { 0x0d, KEY_7 },
27 { 0x0e, KEY_8 },
28 { 0x0f, KEY_9 },
29
30 { 0x00, KEY_POWER },
31 { 0x1b, KEY_AUDIO }, /* Audio Source */
32 { 0x02, KEY_TUNER }, /* TV/FM, not on Y0400052 */
33 { 0x1e, KEY_VIDEO }, /* Video Source */
34 { 0x16, KEY_INFO }, /* Display information */
35 { 0x04, KEY_VOLUMEUP },
36 { 0x08, KEY_VOLUMEDOWN },
37 { 0x0c, KEY_CHANNELUP },
38 { 0x10, KEY_CHANNELDOWN },
39 { 0x03, KEY_ZOOM }, /* fullscreen */
40 { 0x1f, KEY_TEXT }, /* closed caption/teletext */
41 { 0x20, KEY_SLEEP },
42 { 0x29, KEY_CLEAR }, /* boss key */
43 { 0x14, KEY_MUTE },
44 { 0x2b, KEY_RED },
45 { 0x2c, KEY_GREEN },
46 { 0x2d, KEY_YELLOW },
47 { 0x2e, KEY_BLUE },
48 { 0x18, KEY_KPPLUS }, /* fine tune + , not on Y040052 */
49 { 0x19, KEY_KPMINUS }, /* fine tune - , not on Y040052 */
50 { 0x2a, KEY_MEDIA }, /* PIP (Picture in picture */
51 { 0x21, KEY_DOT },
52 { 0x13, KEY_ENTER },
53 { 0x11, KEY_LAST }, /* Recall (last channel */
54 { 0x22, KEY_PREVIOUS },
55 { 0x23, KEY_PLAYPAUSE },
56 { 0x24, KEY_NEXT },
57 { 0x25, KEY_TIME }, /* Time Shifting */
58 { 0x26, KEY_STOP },
59 { 0x27, KEY_RECORD },
60 { 0x28, KEY_SAVE }, /* Screenshot */
61 { 0x2f, KEY_MENU },
62 { 0x30, KEY_CANCEL },
63 { 0x31, KEY_CHANNEL }, /* Channel Surf */
64 { 0x32, KEY_SUBTITLE },
65 { 0x33, KEY_LANGUAGE },
66 { 0x34, KEY_REWIND },
67 { 0x35, KEY_FASTFORWARD },
68 { 0x36, KEY_TV },
69 { 0x37, KEY_RADIO }, /* FM */
70 { 0x38, KEY_DVD },
71
72 { 0x1a, KEY_MODE}, /* change to MCE mode on Y04G0051 */
73 { 0x3e, KEY_F21 }, /* MCE +VOL, on Y04G0033 */
74 { 0x3a, KEY_F22 }, /* MCE -VOL, on Y04G0033 */
75 { 0x3b, KEY_F23 }, /* MCE +CH, on Y04G0033 */
76 { 0x3f, KEY_F24 } /* MCE -CH, on Y04G0033 */
77};
78
79static struct rc_map_list winfast_map = {
80 .map = {
81 .scan = winfast,
82 .size = ARRAY_SIZE(winfast),
83 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
84 .name = RC_MAP_WINFAST,
85 }
86};
87
88static int __init init_rc_map_winfast(void)
89{
90 return rc_map_register(&winfast_map);
91}
92
93static void __exit exit_rc_map_winfast(void)
94{
95 rc_map_unregister(&winfast_map);
96}
97
98module_init(init_rc_map_winfast)
99module_exit(exit_rc_map_winfast)
100
101MODULE_LICENSE("GPL");
102MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
new file mode 100644
index 000000000000..fd237ab120bb
--- /dev/null
+++ b/drivers/media/rc/lirc_dev.c
@@ -0,0 +1,816 @@
1/*
2 * LIRC base driver
3 *
4 * by Artur Lipowski <alipowski@interia.pl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/kernel.h>
24#include <linux/sched.h>
25#include <linux/errno.h>
26#include <linux/ioctl.h>
27#include <linux/fs.h>
28#include <linux/poll.h>
29#include <linux/completion.h>
30#include <linux/mutex.h>
31#include <linux/wait.h>
32#include <linux/unistd.h>
33#include <linux/kthread.h>
34#include <linux/bitops.h>
35#include <linux/device.h>
36#include <linux/cdev.h>
37
38#include <media/lirc.h>
39#include <media/lirc_dev.h>
40
41static int debug;
42
43#define IRCTL_DEV_NAME "BaseRemoteCtl"
44#define NOPLUG -1
45#define LOGHEAD "lirc_dev (%s[%d]): "
46
47static dev_t lirc_base_dev;
48
49struct irctl {
50 struct lirc_driver d;
51 int attached;
52 int open;
53
54 struct mutex irctl_lock;
55 struct lirc_buffer *buf;
56 unsigned int chunk_size;
57
58 struct task_struct *task;
59 long jiffies_to_wait;
60};
61
62static DEFINE_MUTEX(lirc_dev_lock);
63
64static struct irctl *irctls[MAX_IRCTL_DEVICES];
65static struct cdev cdevs[MAX_IRCTL_DEVICES];
66
67/* Only used for sysfs but defined to void otherwise */
68static struct class *lirc_class;
69
70/* helper function
71 * initializes the irctl structure
72 */
73static void lirc_irctl_init(struct irctl *ir)
74{
75 mutex_init(&ir->irctl_lock);
76 ir->d.minor = NOPLUG;
77}
78
79static void lirc_irctl_cleanup(struct irctl *ir)
80{
81 dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
82
83 device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
84
85 if (ir->buf != ir->d.rbuf) {
86 lirc_buffer_free(ir->buf);
87 kfree(ir->buf);
88 }
89 ir->buf = NULL;
90}
91
92/* helper function
93 * reads key codes from driver and puts them into buffer
94 * returns 0 on success
95 */
96static int lirc_add_to_buf(struct irctl *ir)
97{
98 if (ir->d.add_to_buf) {
99 int res = -ENODATA;
100 int got_data = 0;
101
102 /*
103 * service the device as long as it is returning
104 * data and we have space
105 */
106get_data:
107 res = ir->d.add_to_buf(ir->d.data, ir->buf);
108 if (res == 0) {
109 got_data++;
110 goto get_data;
111 }
112
113 if (res == -ENODEV)
114 kthread_stop(ir->task);
115
116 return got_data ? 0 : res;
117 }
118
119 return 0;
120}
121
122/* main function of the polling thread
123 */
124static int lirc_thread(void *irctl)
125{
126 struct irctl *ir = irctl;
127
128 dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n",
129 ir->d.name, ir->d.minor);
130
131 do {
132 if (ir->open) {
133 if (ir->jiffies_to_wait) {
134 set_current_state(TASK_INTERRUPTIBLE);
135 schedule_timeout(ir->jiffies_to_wait);
136 }
137 if (kthread_should_stop())
138 break;
139 if (!lirc_add_to_buf(ir))
140 wake_up_interruptible(&ir->buf->wait_poll);
141 } else {
142 set_current_state(TASK_INTERRUPTIBLE);
143 schedule();
144 }
145 } while (!kthread_should_stop());
146
147 dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n",
148 ir->d.name, ir->d.minor);
149
150 return 0;
151}
152
153
154static struct file_operations lirc_dev_fops = {
155 .owner = THIS_MODULE,
156 .read = lirc_dev_fop_read,
157 .write = lirc_dev_fop_write,
158 .poll = lirc_dev_fop_poll,
159 .unlocked_ioctl = lirc_dev_fop_ioctl,
160#ifdef CONFIG_COMPAT
161 .compat_ioctl = lirc_dev_fop_ioctl,
162#endif
163 .open = lirc_dev_fop_open,
164 .release = lirc_dev_fop_close,
165 .llseek = noop_llseek,
166};
167
168static int lirc_cdev_add(struct irctl *ir)
169{
170 int retval;
171 struct lirc_driver *d = &ir->d;
172 struct cdev *cdev = &cdevs[d->minor];
173
174 if (d->fops) {
175 cdev_init(cdev, d->fops);
176 cdev->owner = d->owner;
177 } else {
178 cdev_init(cdev, &lirc_dev_fops);
179 cdev->owner = THIS_MODULE;
180 }
181 retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
182 if (retval)
183 return retval;
184
185 retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
186 if (retval)
187 kobject_put(&cdev->kobj);
188
189 return retval;
190}
191
192int lirc_register_driver(struct lirc_driver *d)
193{
194 struct irctl *ir;
195 int minor;
196 int bytes_in_key;
197 unsigned int chunk_size;
198 unsigned int buffer_size;
199 int err;
200
201 if (!d) {
202 printk(KERN_ERR "lirc_dev: lirc_register_driver: "
203 "driver pointer must be not NULL!\n");
204 err = -EBADRQC;
205 goto out;
206 }
207
208 if (!d->dev) {
209 printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
210 err = -EINVAL;
211 goto out;
212 }
213
214 if (MAX_IRCTL_DEVICES <= d->minor) {
215 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
216 "\"minor\" must be between 0 and %d (%d)!\n",
217 MAX_IRCTL_DEVICES-1, d->minor);
218 err = -EBADRQC;
219 goto out;
220 }
221
222 if (1 > d->code_length || (BUFLEN * 8) < d->code_length) {
223 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
224 "code length in bits for minor (%d) "
225 "must be less than %d!\n",
226 d->minor, BUFLEN * 8);
227 err = -EBADRQC;
228 goto out;
229 }
230
231 dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n",
232 d->sample_rate);
233 if (d->sample_rate) {
234 if (2 > d->sample_rate || HZ < d->sample_rate) {
235 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
236 "sample_rate must be between 2 and %d!\n", HZ);
237 err = -EBADRQC;
238 goto out;
239 }
240 if (!d->add_to_buf) {
241 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
242 "add_to_buf cannot be NULL when "
243 "sample_rate is set\n");
244 err = -EBADRQC;
245 goto out;
246 }
247 } else if (!(d->fops && d->fops->read) && !d->rbuf) {
248 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
249 "fops->read and rbuf cannot all be NULL!\n");
250 err = -EBADRQC;
251 goto out;
252 } else if (!d->rbuf) {
253 if (!(d->fops && d->fops->read && d->fops->poll &&
254 d->fops->unlocked_ioctl)) {
255 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
256 "neither read, poll nor unlocked_ioctl can be NULL!\n");
257 err = -EBADRQC;
258 goto out;
259 }
260 }
261
262 mutex_lock(&lirc_dev_lock);
263
264 minor = d->minor;
265
266 if (minor < 0) {
267 /* find first free slot for driver */
268 for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++)
269 if (!irctls[minor])
270 break;
271 if (MAX_IRCTL_DEVICES == minor) {
272 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
273 "no free slots for drivers!\n");
274 err = -ENOMEM;
275 goto out_lock;
276 }
277 } else if (irctls[minor]) {
278 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
279 "minor (%d) just registered!\n", minor);
280 err = -EBUSY;
281 goto out_lock;
282 }
283
284 ir = kzalloc(sizeof(struct irctl), GFP_KERNEL);
285 if (!ir) {
286 err = -ENOMEM;
287 goto out_lock;
288 }
289 lirc_irctl_init(ir);
290 irctls[minor] = ir;
291 d->minor = minor;
292
293 if (d->sample_rate) {
294 ir->jiffies_to_wait = HZ / d->sample_rate;
295 } else {
296 /* it means - wait for external event in task queue */
297 ir->jiffies_to_wait = 0;
298 }
299
300 /* some safety check 8-) */
301 d->name[sizeof(d->name)-1] = '\0';
302
303 bytes_in_key = BITS_TO_LONGS(d->code_length) +
304 (d->code_length % 8 ? 1 : 0);
305 buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
306 chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key;
307
308 if (d->rbuf) {
309 ir->buf = d->rbuf;
310 } else {
311 ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
312 if (!ir->buf) {
313 err = -ENOMEM;
314 goto out_lock;
315 }
316 err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
317 if (err) {
318 kfree(ir->buf);
319 goto out_lock;
320 }
321 }
322 ir->chunk_size = ir->buf->chunk_size;
323
324 if (d->features == 0)
325 d->features = LIRC_CAN_REC_LIRCCODE;
326
327 ir->d = *d;
328
329 device_create(lirc_class, ir->d.dev,
330 MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
331 "lirc%u", ir->d.minor);
332
333 if (d->sample_rate) {
334 /* try to fire up polling thread */
335 ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev");
336 if (IS_ERR(ir->task)) {
337 dev_err(d->dev, "lirc_dev: lirc_register_driver: "
338 "cannot run poll thread for minor = %d\n",
339 d->minor);
340 err = -ECHILD;
341 goto out_sysfs;
342 }
343 }
344
345 err = lirc_cdev_add(ir);
346 if (err)
347 goto out_sysfs;
348
349 ir->attached = 1;
350 mutex_unlock(&lirc_dev_lock);
351
352 dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
353 ir->d.name, ir->d.minor);
354 return minor;
355
356out_sysfs:
357 device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
358out_lock:
359 mutex_unlock(&lirc_dev_lock);
360out:
361 return err;
362}
363EXPORT_SYMBOL(lirc_register_driver);
364
365int lirc_unregister_driver(int minor)
366{
367 struct irctl *ir;
368 struct cdev *cdev;
369
370 if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
371 printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
372 "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1);
373 return -EBADRQC;
374 }
375
376 ir = irctls[minor];
377 if (!ir) {
378 printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct "
379 "for minor %d!\n", __func__, minor);
380 return -ENOENT;
381 }
382
383 cdev = &cdevs[minor];
384
385 mutex_lock(&lirc_dev_lock);
386
387 if (ir->d.minor != minor) {
388 printk(KERN_ERR "lirc_dev: %s: minor (%d) device not "
389 "registered!\n", __func__, minor);
390 mutex_unlock(&lirc_dev_lock);
391 return -ENOENT;
392 }
393
394 /* end up polling thread */
395 if (ir->task)
396 kthread_stop(ir->task);
397
398 dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
399 ir->d.name, ir->d.minor);
400
401 ir->attached = 0;
402 if (ir->open) {
403 dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
404 ir->d.name, ir->d.minor);
405 wake_up_interruptible(&ir->buf->wait_poll);
406 mutex_lock(&ir->irctl_lock);
407 ir->d.set_use_dec(ir->d.data);
408 module_put(cdev->owner);
409 mutex_unlock(&ir->irctl_lock);
410 } else {
411 lirc_irctl_cleanup(ir);
412 cdev_del(cdev);
413 kfree(ir);
414 irctls[minor] = NULL;
415 }
416
417 mutex_unlock(&lirc_dev_lock);
418
419 return 0;
420}
421EXPORT_SYMBOL(lirc_unregister_driver);
422
423int lirc_dev_fop_open(struct inode *inode, struct file *file)
424{
425 struct irctl *ir;
426 struct cdev *cdev;
427 int retval = 0;
428
429 if (iminor(inode) >= MAX_IRCTL_DEVICES) {
430 printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n",
431 iminor(inode));
432 return -ENODEV;
433 }
434
435 if (mutex_lock_interruptible(&lirc_dev_lock))
436 return -ERESTARTSYS;
437
438 ir = irctls[iminor(inode)];
439 if (!ir) {
440 retval = -ENODEV;
441 goto error;
442 }
443
444 dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
445
446 if (ir->d.minor == NOPLUG) {
447 retval = -ENODEV;
448 goto error;
449 }
450
451 if (ir->open) {
452 retval = -EBUSY;
453 goto error;
454 }
455
456 cdev = &cdevs[iminor(inode)];
457 if (try_module_get(cdev->owner)) {
458 ir->open++;
459 retval = ir->d.set_use_inc(ir->d.data);
460
461 if (retval) {
462 module_put(cdev->owner);
463 ir->open--;
464 } else {
465 lirc_buffer_clear(ir->buf);
466 }
467 if (ir->task)
468 wake_up_process(ir->task);
469 }
470
471error:
472 if (ir)
473 dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n",
474 ir->d.name, ir->d.minor, retval);
475
476 mutex_unlock(&lirc_dev_lock);
477
478 nonseekable_open(inode, file);
479
480 return retval;
481}
482EXPORT_SYMBOL(lirc_dev_fop_open);
483
484int lirc_dev_fop_close(struct inode *inode, struct file *file)
485{
486 struct irctl *ir = irctls[iminor(inode)];
487 struct cdev *cdev = &cdevs[iminor(inode)];
488
489 if (!ir) {
490 printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
491 return -EINVAL;
492 }
493
494 dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
495
496 WARN_ON(mutex_lock_killable(&lirc_dev_lock));
497
498 ir->open--;
499 if (ir->attached) {
500 ir->d.set_use_dec(ir->d.data);
501 module_put(cdev->owner);
502 } else {
503 lirc_irctl_cleanup(ir);
504 cdev_del(cdev);
505 irctls[ir->d.minor] = NULL;
506 kfree(ir);
507 }
508
509 mutex_unlock(&lirc_dev_lock);
510
511 return 0;
512}
513EXPORT_SYMBOL(lirc_dev_fop_close);
514
515unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
516{
517 struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
518 unsigned int ret;
519
520 if (!ir) {
521 printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
522 return POLLERR;
523 }
524
525 dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
526
527 if (!ir->attached)
528 return POLLERR;
529
530 poll_wait(file, &ir->buf->wait_poll, wait);
531
532 if (ir->buf)
533 if (lirc_buffer_empty(ir->buf))
534 ret = 0;
535 else
536 ret = POLLIN | POLLRDNORM;
537 else
538 ret = POLLERR;
539
540 dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
541 ir->d.name, ir->d.minor, ret);
542
543 return ret;
544}
545EXPORT_SYMBOL(lirc_dev_fop_poll);
546
547long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
548{
549 __u32 mode;
550 int result = 0;
551 struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
552
553 if (!ir) {
554 printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
555 return -ENODEV;
556 }
557
558 dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
559 ir->d.name, ir->d.minor, cmd);
560
561 if (ir->d.minor == NOPLUG || !ir->attached) {
562 dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
563 ir->d.name, ir->d.minor);
564 return -ENODEV;
565 }
566
567 mutex_lock(&ir->irctl_lock);
568
569 switch (cmd) {
570 case LIRC_GET_FEATURES:
571 result = put_user(ir->d.features, (__u32 *)arg);
572 break;
573 case LIRC_GET_REC_MODE:
574 if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
575 result = -ENOSYS;
576 break;
577 }
578
579 result = put_user(LIRC_REC2MODE
580 (ir->d.features & LIRC_CAN_REC_MASK),
581 (__u32 *)arg);
582 break;
583 case LIRC_SET_REC_MODE:
584 if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
585 result = -ENOSYS;
586 break;
587 }
588
589 result = get_user(mode, (__u32 *)arg);
590 if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
591 result = -EINVAL;
592 /*
593 * FIXME: We should actually set the mode somehow but
594 * for now, lirc_serial doesn't support mode changing either
595 */
596 break;
597 case LIRC_GET_LENGTH:
598 result = put_user(ir->d.code_length, (__u32 *)arg);
599 break;
600 case LIRC_GET_MIN_TIMEOUT:
601 if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
602 ir->d.min_timeout == 0) {
603 result = -ENOSYS;
604 break;
605 }
606
607 result = put_user(ir->d.min_timeout, (__u32 *)arg);
608 break;
609 case LIRC_GET_MAX_TIMEOUT:
610 if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
611 ir->d.max_timeout == 0) {
612 result = -ENOSYS;
613 break;
614 }
615
616 result = put_user(ir->d.max_timeout, (__u32 *)arg);
617 break;
618 default:
619 result = -EINVAL;
620 }
621
622 dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n",
623 ir->d.name, ir->d.minor, result);
624
625 mutex_unlock(&ir->irctl_lock);
626
627 return result;
628}
629EXPORT_SYMBOL(lirc_dev_fop_ioctl);
630
631ssize_t lirc_dev_fop_read(struct file *file,
632 char __user *buffer,
633 size_t length,
634 loff_t *ppos)
635{
636 struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
637 unsigned char *buf;
638 int ret = 0, written = 0;
639 DECLARE_WAITQUEUE(wait, current);
640
641 if (!ir) {
642 printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
643 return -ENODEV;
644 }
645
646 dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
647
648 buf = kzalloc(ir->chunk_size, GFP_KERNEL);
649 if (!buf)
650 return -ENOMEM;
651
652 if (mutex_lock_interruptible(&ir->irctl_lock)) {
653 ret = -ERESTARTSYS;
654 goto out_unlocked;
655 }
656 if (!ir->attached) {
657 ret = -ENODEV;
658 goto out_locked;
659 }
660
661 if (length % ir->chunk_size) {
662 ret = -EINVAL;
663 goto out_locked;
664 }
665
666 /*
667 * we add ourselves to the task queue before buffer check
668 * to avoid losing scan code (in case when queue is awaken somewhere
669 * between while condition checking and scheduling)
670 */
671 add_wait_queue(&ir->buf->wait_poll, &wait);
672 set_current_state(TASK_INTERRUPTIBLE);
673
674 /*
675 * while we didn't provide 'length' bytes, device is opened in blocking
676 * mode and 'copy_to_user' is happy, wait for data.
677 */
678 while (written < length && ret == 0) {
679 if (lirc_buffer_empty(ir->buf)) {
680 /* According to the read(2) man page, 'written' can be
681 * returned as less than 'length', instead of blocking
682 * again, returning -EWOULDBLOCK, or returning
683 * -ERESTARTSYS */
684 if (written)
685 break;
686 if (file->f_flags & O_NONBLOCK) {
687 ret = -EWOULDBLOCK;
688 break;
689 }
690 if (signal_pending(current)) {
691 ret = -ERESTARTSYS;
692 break;
693 }
694
695 mutex_unlock(&ir->irctl_lock);
696 schedule();
697 set_current_state(TASK_INTERRUPTIBLE);
698
699 if (mutex_lock_interruptible(&ir->irctl_lock)) {
700 ret = -ERESTARTSYS;
701 remove_wait_queue(&ir->buf->wait_poll, &wait);
702 set_current_state(TASK_RUNNING);
703 goto out_unlocked;
704 }
705
706 if (!ir->attached) {
707 ret = -ENODEV;
708 break;
709 }
710 } else {
711 lirc_buffer_read(ir->buf, buf);
712 ret = copy_to_user((void *)buffer+written, buf,
713 ir->buf->chunk_size);
714 if (!ret)
715 written += ir->buf->chunk_size;
716 else
717 ret = -EFAULT;
718 }
719 }
720
721 remove_wait_queue(&ir->buf->wait_poll, &wait);
722 set_current_state(TASK_RUNNING);
723
724out_locked:
725 mutex_unlock(&ir->irctl_lock);
726
727out_unlocked:
728 kfree(buf);
729 dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
730 ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret);
731
732 return ret ? ret : written;
733}
734EXPORT_SYMBOL(lirc_dev_fop_read);
735
736void *lirc_get_pdata(struct file *file)
737{
738 void *data = NULL;
739
740 if (file && file->f_dentry && file->f_dentry->d_inode &&
741 file->f_dentry->d_inode->i_rdev) {
742 struct irctl *ir;
743 ir = irctls[iminor(file->f_dentry->d_inode)];
744 data = ir->d.data;
745 }
746
747 return data;
748}
749EXPORT_SYMBOL(lirc_get_pdata);
750
751
752ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
753 size_t length, loff_t *ppos)
754{
755 struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
756
757 if (!ir) {
758 printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
759 return -ENODEV;
760 }
761
762 dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
763
764 if (!ir->attached)
765 return -ENODEV;
766
767 return -EINVAL;
768}
769EXPORT_SYMBOL(lirc_dev_fop_write);
770
771
772static int __init lirc_dev_init(void)
773{
774 int retval;
775
776 lirc_class = class_create(THIS_MODULE, "lirc");
777 if (IS_ERR(lirc_class)) {
778 retval = PTR_ERR(lirc_class);
779 printk(KERN_ERR "lirc_dev: class_create failed\n");
780 goto error;
781 }
782
783 retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
784 IRCTL_DEV_NAME);
785 if (retval) {
786 class_destroy(lirc_class);
787 printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n");
788 goto error;
789 }
790
791
792 printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, "
793 "major %d \n", MAJOR(lirc_base_dev));
794
795error:
796 return retval;
797}
798
799
800
801static void __exit lirc_dev_exit(void)
802{
803 class_destroy(lirc_class);
804 unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
805 printk(KERN_INFO "lirc_dev: module unloaded\n");
806}
807
808module_init(lirc_dev_init);
809module_exit(lirc_dev_exit);
810
811MODULE_DESCRIPTION("LIRC base driver module");
812MODULE_AUTHOR("Artur Lipowski");
813MODULE_LICENSE("GPL");
814
815module_param(debug, bool, S_IRUGO | S_IWUSR);
816MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
new file mode 100644
index 000000000000..0fef6efad537
--- /dev/null
+++ b/drivers/media/rc/mceusb.c
@@ -0,0 +1,1313 @@
1/*
2 * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
3 *
4 * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
5 *
6 * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
7 * Conti, Martin Blatter and Daniel Melander, the latter of which was
8 * in turn also based on the lirc_atiusb driver by Paul Miller. The
9 * two mce drivers were merged into one by Jarod Wilson, with transmit
10 * support for the 1st-gen device added primarily by Patrick Calhoun,
11 * with a bit of tweaks by Jarod. Debugging improvements and proper
12 * support for what appears to be 3rd-gen hardware added by Jarod.
13 * Initial port from lirc driver to ir-core drivery by Jarod, based
14 * partially on a port to an earlier proposed IR infrastructure by
15 * Jon Smirl, which included enhancements and simplifications to the
16 * incoming IR buffer parsing routines.
17 *
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 *
33 */
34
35#include <linux/device.h>
36#include <linux/module.h>
37#include <linux/slab.h>
38#include <linux/usb.h>
39#include <linux/usb/input.h>
40#include <media/rc-core.h>
41
42#define DRIVER_VERSION "1.91"
43#define DRIVER_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
44#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \
45 "device driver"
46#define DRIVER_NAME "mceusb"
47
48#define USB_BUFLEN 32 /* USB reception buffer length */
49#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
50#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
51#define MS_TO_NS(msec) ((msec) * 1000)
52
53/* MCE constants */
54#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
55#define MCE_TIME_UNIT 50 /* Approx 50us resolution */
56#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */
57#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
58#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
59#define MCE_IRDATA_TRAILER 0x80 /* End of IR data */
60#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
61#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
62#define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */
63#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
64#define MCE_PULSE_MASK 0x7f /* Pulse mask */
65#define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */
66
67#define MCE_HW_CMD_HEADER 0xff /* MCE hardware command header */
68#define MCE_COMMAND_HEADER 0x9f /* MCE command header */
69#define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */
70#define MCE_COMMAND_NULL 0x00 /* These show up various places... */
71/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
72 * then we're looking at a raw IR data sample */
73#define MCE_COMMAND_IRDATA 0x80
74#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
75
76/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
77#define MCE_CMD_SIG_END 0x01 /* End of signal */
78#define MCE_CMD_PING 0x03 /* Ping device */
79#define MCE_CMD_UNKNOWN 0x04 /* Unknown */
80#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */
81#define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */
82#define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */
83#define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */
84#define MCE_CMD_UNKNOWN3 0x09 /* Unknown */
85#define MCE_CMD_UNKNOWN4 0x0a /* Unknown */
86#define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */
87#define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */
88#define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */
89#define MCE_CMD_UNKNOWN5 0x0e /* Unknown */
90#define MCE_CMD_UNKNOWN6 0x0f /* Unknown */
91#define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */
92#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */
93#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */
94#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */
95#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */
96#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */
97#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */
98#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */
99#define MCE_CMD_UNKNOWN8 0x19 /* Unknown */
100#define MCE_CMD_UNKNOWN9 0x1b /* Unknown */
101#define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */
102#define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */
103
104
105/* module parameters */
106#ifdef CONFIG_USB_DEBUG
107static int debug = 1;
108#else
109static int debug;
110#endif
111
112/* general constants */
113#define SEND_FLAG_IN_PROGRESS 1
114#define SEND_FLAG_COMPLETE 2
115#define RECV_FLAG_IN_PROGRESS 3
116#define RECV_FLAG_COMPLETE 4
117
118#define MCEUSB_RX 1
119#define MCEUSB_TX 2
120
121#define VENDOR_PHILIPS 0x0471
122#define VENDOR_SMK 0x0609
123#define VENDOR_TATUNG 0x1460
124#define VENDOR_GATEWAY 0x107b
125#define VENDOR_SHUTTLE 0x1308
126#define VENDOR_SHUTTLE2 0x051c
127#define VENDOR_MITSUMI 0x03ee
128#define VENDOR_TOPSEED 0x1784
129#define VENDOR_RICAVISION 0x179d
130#define VENDOR_ITRON 0x195d
131#define VENDOR_FIC 0x1509
132#define VENDOR_LG 0x043e
133#define VENDOR_MICROSOFT 0x045e
134#define VENDOR_FORMOSA 0x147a
135#define VENDOR_FINTEK 0x1934
136#define VENDOR_PINNACLE 0x2304
137#define VENDOR_ECS 0x1019
138#define VENDOR_WISTRON 0x0fb8
139#define VENDOR_COMPRO 0x185b
140#define VENDOR_NORTHSTAR 0x04eb
141#define VENDOR_REALTEK 0x0bda
142#define VENDOR_TIVO 0x105a
143#define VENDOR_CONEXANT 0x0572
144
145enum mceusb_model_type {
146 MCE_GEN2 = 0, /* Most boards */
147 MCE_GEN1,
148 MCE_GEN3,
149 MCE_GEN2_TX_INV,
150 POLARIS_EVK,
151 CX_HYBRID_TV,
152};
153
154struct mceusb_model {
155 u32 mce_gen1:1;
156 u32 mce_gen2:1;
157 u32 mce_gen3:1;
158 u32 tx_mask_normal:1;
159 u32 is_polaris:1;
160 u32 no_tx:1;
161
162 const char *rc_map; /* Allow specify a per-board map */
163 const char *name; /* per-board name */
164};
165
166static const struct mceusb_model mceusb_model[] = {
167 [MCE_GEN1] = {
168 .mce_gen1 = 1,
169 .tx_mask_normal = 1,
170 },
171 [MCE_GEN2] = {
172 .mce_gen2 = 1,
173 },
174 [MCE_GEN2_TX_INV] = {
175 .mce_gen2 = 1,
176 .tx_mask_normal = 1,
177 },
178 [MCE_GEN3] = {
179 .mce_gen3 = 1,
180 .tx_mask_normal = 1,
181 },
182 [POLARIS_EVK] = {
183 .is_polaris = 1,
184 /*
185 * In fact, the EVK is shipped without
186 * remotes, but we should have something handy,
187 * to allow testing it
188 */
189 .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
190 .name = "Conexant Hybrid TV (cx231xx) MCE IR",
191 },
192 [CX_HYBRID_TV] = {
193 .is_polaris = 1,
194 .no_tx = 1, /* tx isn't wired up at all */
195 .name = "Conexant Hybrid TV (cx231xx) MCE IR",
196 },
197};
198
199static struct usb_device_id mceusb_dev_table[] = {
200 /* Original Microsoft MCE IR Transceiver (often HP-branded) */
201 { USB_DEVICE(VENDOR_MICROSOFT, 0x006d),
202 .driver_info = MCE_GEN1 },
203 /* Philips Infrared Transceiver - Sahara branded */
204 { USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
205 /* Philips Infrared Transceiver - HP branded */
206 { USB_DEVICE(VENDOR_PHILIPS, 0x060c),
207 .driver_info = MCE_GEN2_TX_INV },
208 /* Philips SRM5100 */
209 { USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
210 /* Philips Infrared Transceiver - Omaura */
211 { USB_DEVICE(VENDOR_PHILIPS, 0x060f) },
212 /* Philips Infrared Transceiver - Spinel plus */
213 { USB_DEVICE(VENDOR_PHILIPS, 0x0613) },
214 /* Philips eHome Infrared Transceiver */
215 { USB_DEVICE(VENDOR_PHILIPS, 0x0815) },
216 /* Philips/Spinel plus IR transceiver for ASUS */
217 { USB_DEVICE(VENDOR_PHILIPS, 0x206c) },
218 /* Philips/Spinel plus IR transceiver for ASUS */
219 { USB_DEVICE(VENDOR_PHILIPS, 0x2088) },
220 /* Realtek MCE IR Receiver */
221 { USB_DEVICE(VENDOR_REALTEK, 0x0161) },
222 /* SMK/Toshiba G83C0004D410 */
223 { USB_DEVICE(VENDOR_SMK, 0x031d),
224 .driver_info = MCE_GEN2_TX_INV },
225 /* SMK eHome Infrared Transceiver (Sony VAIO) */
226 { USB_DEVICE(VENDOR_SMK, 0x0322),
227 .driver_info = MCE_GEN2_TX_INV },
228 /* bundled with Hauppauge PVR-150 */
229 { USB_DEVICE(VENDOR_SMK, 0x0334),
230 .driver_info = MCE_GEN2_TX_INV },
231 /* SMK eHome Infrared Transceiver */
232 { USB_DEVICE(VENDOR_SMK, 0x0338) },
233 /* Tatung eHome Infrared Transceiver */
234 { USB_DEVICE(VENDOR_TATUNG, 0x9150) },
235 /* Shuttle eHome Infrared Transceiver */
236 { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) },
237 /* Shuttle eHome Infrared Transceiver */
238 { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) },
239 /* Gateway eHome Infrared Transceiver */
240 { USB_DEVICE(VENDOR_GATEWAY, 0x3009) },
241 /* Mitsumi */
242 { USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
243 /* Topseed eHome Infrared Transceiver */
244 { USB_DEVICE(VENDOR_TOPSEED, 0x0001),
245 .driver_info = MCE_GEN2_TX_INV },
246 /* Topseed HP eHome Infrared Transceiver */
247 { USB_DEVICE(VENDOR_TOPSEED, 0x0006),
248 .driver_info = MCE_GEN2_TX_INV },
249 /* Topseed eHome Infrared Transceiver */
250 { USB_DEVICE(VENDOR_TOPSEED, 0x0007),
251 .driver_info = MCE_GEN2_TX_INV },
252 /* Topseed eHome Infrared Transceiver */
253 { USB_DEVICE(VENDOR_TOPSEED, 0x0008),
254 .driver_info = MCE_GEN3 },
255 /* Topseed eHome Infrared Transceiver */
256 { USB_DEVICE(VENDOR_TOPSEED, 0x000a),
257 .driver_info = MCE_GEN2_TX_INV },
258 /* Topseed eHome Infrared Transceiver */
259 { USB_DEVICE(VENDOR_TOPSEED, 0x0011),
260 .driver_info = MCE_GEN2_TX_INV },
261 /* Ricavision internal Infrared Transceiver */
262 { USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
263 /* Itron ione Libra Q-11 */
264 { USB_DEVICE(VENDOR_ITRON, 0x7002) },
265 /* FIC eHome Infrared Transceiver */
266 { USB_DEVICE(VENDOR_FIC, 0x9242) },
267 /* LG eHome Infrared Transceiver */
268 { USB_DEVICE(VENDOR_LG, 0x9803) },
269 /* Microsoft MCE Infrared Transceiver */
270 { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) },
271 /* Formosa eHome Infrared Transceiver */
272 { USB_DEVICE(VENDOR_FORMOSA, 0xe015) },
273 /* Formosa21 / eHome Infrared Receiver */
274 { USB_DEVICE(VENDOR_FORMOSA, 0xe016) },
275 /* Formosa aim / Trust MCE Infrared Receiver */
276 { USB_DEVICE(VENDOR_FORMOSA, 0xe017) },
277 /* Formosa Industrial Computing / Beanbag Emulation Device */
278 { USB_DEVICE(VENDOR_FORMOSA, 0xe018) },
279 /* Formosa21 / eHome Infrared Receiver */
280 { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) },
281 /* Formosa Industrial Computing AIM IR605/A */
282 { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
283 /* Formosa Industrial Computing */
284 { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
285 /* Fintek eHome Infrared Transceiver (HP branded) */
286 { USB_DEVICE(VENDOR_FINTEK, 0x5168) },
287 /* Fintek eHome Infrared Transceiver */
288 { USB_DEVICE(VENDOR_FINTEK, 0x0602) },
289 /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
290 { USB_DEVICE(VENDOR_FINTEK, 0x0702) },
291 /* Pinnacle Remote Kit */
292 { USB_DEVICE(VENDOR_PINNACLE, 0x0225),
293 .driver_info = MCE_GEN3 },
294 /* Elitegroup Computer Systems IR */
295 { USB_DEVICE(VENDOR_ECS, 0x0f38) },
296 /* Wistron Corp. eHome Infrared Receiver */
297 { USB_DEVICE(VENDOR_WISTRON, 0x0002) },
298 /* Compro K100 */
299 { USB_DEVICE(VENDOR_COMPRO, 0x3020) },
300 /* Compro K100 v2 */
301 { USB_DEVICE(VENDOR_COMPRO, 0x3082) },
302 /* Northstar Systems, Inc. eHome Infrared Transceiver */
303 { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
304 /* TiVo PC IR Receiver */
305 { USB_DEVICE(VENDOR_TIVO, 0x2000) },
306 /* Conexant Hybrid TV "Shelby" Polaris SDK */
307 { USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
308 .driver_info = POLARIS_EVK },
309 /* Conexant Hybrid TV RDU253S Polaris */
310 { USB_DEVICE(VENDOR_CONEXANT, 0x58a5),
311 .driver_info = CX_HYBRID_TV },
312 /* Terminating entry */
313 { }
314};
315
316/* data structure for each usb transceiver */
317struct mceusb_dev {
318 /* ir-core bits */
319 struct rc_dev *rc;
320
321 /* optional features we can enable */
322 bool carrier_report_enabled;
323 bool learning_enabled;
324
325 /* core device bits */
326 struct device *dev;
327
328 /* usb */
329 struct usb_device *usbdev;
330 struct urb *urb_in;
331 struct usb_endpoint_descriptor *usb_ep_in;
332 struct usb_endpoint_descriptor *usb_ep_out;
333
334 /* buffers and dma */
335 unsigned char *buf_in;
336 unsigned int len_in;
337 dma_addr_t dma_in;
338 dma_addr_t dma_out;
339
340 enum {
341 CMD_HEADER = 0,
342 SUBCMD,
343 CMD_DATA,
344 PARSE_IRDATA,
345 } parser_state;
346
347 u8 cmd, rem; /* Remaining IR data bytes in packet */
348
349 struct {
350 u32 connected:1;
351 u32 tx_mask_normal:1;
352 u32 microsoft_gen1:1;
353 u32 no_tx:1;
354 } flags;
355
356 /* transmit support */
357 int send_flags;
358 u32 carrier;
359 unsigned char tx_mask;
360
361 char name[128];
362 char phys[64];
363 enum mceusb_model_type model;
364};
365
366/*
367 * MCE Device Command Strings
368 * Device command responses vary from device to device...
369 * - DEVICE_RESET resets the hardware to its default state
370 * - GET_REVISION fetches the hardware/software revision, common
371 * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
372 * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
373 * device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
374 * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
375 * ((clk / frequency) - 1)
376 * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
377 * response in the form of 9f 0c msb lsb
378 * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
379 * the form of 9f 08 bm, where bm is the bitmask
380 * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
381 * general use one or short-range learning one, in the form of
382 * 9f 14 ss, where ss is either 01 for long-range or 02 for short
383 * - SET_CARRIER_FREQ sets a new carrier mode and frequency
384 * - SET_TX_BITMASK sets the transmitter bitmask
385 * - SET_RX_TIMEOUT sets the receiver timeout
386 * - SET_RX_SENSOR sets which receiver sensor to use
387 */
388static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
389 MCE_CMD_DEVICE_RESET};
390static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
391static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
392static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
393static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
394static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
395static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
396static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
397/* sub in desired values in lower byte or bytes for full command */
398/* FIXME: make use of these for transmit.
399static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER,
400 MCE_CMD_S_CARRIER, 0x00, 0x00};
401static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
402static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER,
403 MCE_CMD_S_TIMEOUT, 0x00, 0x00};
404static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER,
405 MCE_CMD_S_RXSENSOR, 0x00};
406*/
407
408static int mceusb_cmdsize(u8 cmd, u8 subcmd)
409{
410 int datasize = 0;
411
412 switch (cmd) {
413 case MCE_COMMAND_NULL:
414 if (subcmd == MCE_HW_CMD_HEADER)
415 datasize = 1;
416 break;
417 case MCE_HW_CMD_HEADER:
418 switch (subcmd) {
419 case MCE_CMD_G_REVISION:
420 datasize = 2;
421 break;
422 }
423 case MCE_COMMAND_HEADER:
424 switch (subcmd) {
425 case MCE_CMD_UNKNOWN:
426 case MCE_CMD_S_CARRIER:
427 case MCE_CMD_S_TIMEOUT:
428 case MCE_RSP_PULSE_COUNT:
429 datasize = 2;
430 break;
431 case MCE_CMD_SIG_END:
432 case MCE_CMD_S_TXMASK:
433 case MCE_CMD_S_RXSENSOR:
434 datasize = 1;
435 break;
436 }
437 }
438 return datasize;
439}
440
441static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
442 int offset, int len, bool out)
443{
444 char codes[USB_BUFLEN * 3 + 1];
445 char inout[9];
446 u8 cmd, subcmd, data1, data2;
447 struct device *dev = ir->dev;
448 int i, start, skip = 0;
449
450 if (!debug)
451 return;
452
453 /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
454 if (ir->flags.microsoft_gen1 && !out && !offset)
455 skip = 2;
456
457 if (len <= skip)
458 return;
459
460 for (i = 0; i < len && i < USB_BUFLEN; i++)
461 snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff);
462
463 dev_info(dev, "%sx data: %s(length=%d)\n",
464 (out ? "t" : "r"), codes, len);
465
466 if (out)
467 strcpy(inout, "Request\0");
468 else
469 strcpy(inout, "Got\0");
470
471 start = offset + skip;
472 cmd = buf[start] & 0xff;
473 subcmd = buf[start + 1] & 0xff;
474 data1 = buf[start + 2] & 0xff;
475 data2 = buf[start + 3] & 0xff;
476
477 switch (cmd) {
478 case MCE_COMMAND_NULL:
479 if ((subcmd == MCE_HW_CMD_HEADER) &&
480 (data1 == MCE_CMD_DEVICE_RESET))
481 dev_info(dev, "Device reset requested\n");
482 else
483 dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
484 cmd, subcmd);
485 break;
486 case MCE_HW_CMD_HEADER:
487 switch (subcmd) {
488 case MCE_CMD_G_REVISION:
489 if (len == 2)
490 dev_info(dev, "Get hw/sw rev?\n");
491 else
492 dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
493 "0x%02x 0x%02x\n", data1, data2,
494 buf[start + 4], buf[start + 5]);
495 break;
496 case MCE_CMD_DEVICE_RESET:
497 dev_info(dev, "Device reset requested\n");
498 break;
499 case MCE_RSP_CMD_INVALID:
500 dev_info(dev, "Previous command not supported\n");
501 break;
502 case MCE_CMD_UNKNOWN7:
503 case MCE_CMD_UNKNOWN9:
504 default:
505 dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
506 cmd, subcmd);
507 break;
508 }
509 break;
510 case MCE_COMMAND_HEADER:
511 switch (subcmd) {
512 case MCE_CMD_SIG_END:
513 dev_info(dev, "End of signal\n");
514 break;
515 case MCE_CMD_PING:
516 dev_info(dev, "Ping\n");
517 break;
518 case MCE_CMD_UNKNOWN:
519 dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
520 data1, data2);
521 break;
522 case MCE_CMD_S_CARRIER:
523 dev_info(dev, "%s carrier mode and freq of "
524 "0x%02x 0x%02x\n", inout, data1, data2);
525 break;
526 case MCE_CMD_G_CARRIER:
527 dev_info(dev, "Get carrier mode and freq\n");
528 break;
529 case MCE_CMD_S_TXMASK:
530 dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
531 inout, data1);
532 break;
533 case MCE_CMD_S_TIMEOUT:
534 /* value is in units of 50us, so x*50/100 or x/2 ms */
535 dev_info(dev, "%s receive timeout of %d ms\n",
536 inout, ((data1 << 8) | data2) / 2);
537 break;
538 case MCE_CMD_G_TIMEOUT:
539 dev_info(dev, "Get receive timeout\n");
540 break;
541 case MCE_CMD_G_TXMASK:
542 dev_info(dev, "Get transmit blaster mask\n");
543 break;
544 case MCE_CMD_S_RXSENSOR:
545 dev_info(dev, "%s %s-range receive sensor in use\n",
546 inout, data1 == 0x02 ? "short" : "long");
547 break;
548 case MCE_CMD_G_RXSENSOR:
549 /* aka MCE_RSP_PULSE_COUNT */
550 if (out)
551 dev_info(dev, "Get receive sensor\n");
552 else if (ir->learning_enabled)
553 dev_info(dev, "RX pulse count: %d\n",
554 ((data1 << 8) | data2));
555 break;
556 case MCE_RSP_CMD_INVALID:
557 dev_info(dev, "Error! Hardware is likely wedged...\n");
558 break;
559 case MCE_CMD_UNKNOWN2:
560 case MCE_CMD_UNKNOWN3:
561 case MCE_CMD_UNKNOWN5:
562 default:
563 dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
564 cmd, subcmd);
565 break;
566 }
567 break;
568 default:
569 break;
570 }
571
572 if (cmd == MCE_IRDATA_TRAILER)
573 dev_info(dev, "End of raw IR data\n");
574 else if ((cmd != MCE_COMMAND_HEADER) &&
575 ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
576 dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
577}
578
579static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
580{
581 struct mceusb_dev *ir;
582 int len;
583
584 if (!urb)
585 return;
586
587 ir = urb->context;
588 if (ir) {
589 len = urb->actual_length;
590
591 dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
592 urb->status, len);
593
594 mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
595 }
596
597}
598
599/* request incoming or send outgoing usb packet - used to initialize remote */
600static void mce_request_packet(struct mceusb_dev *ir,
601 struct usb_endpoint_descriptor *ep,
602 unsigned char *data, int size, int urb_type)
603{
604 int res;
605 struct urb *async_urb;
606 struct device *dev = ir->dev;
607 unsigned char *async_buf;
608
609 if (urb_type == MCEUSB_TX) {
610 async_urb = usb_alloc_urb(0, GFP_KERNEL);
611 if (unlikely(!async_urb)) {
612 dev_err(dev, "Error, couldn't allocate urb!\n");
613 return;
614 }
615
616 async_buf = kzalloc(size, GFP_KERNEL);
617 if (!async_buf) {
618 dev_err(dev, "Error, couldn't allocate buf!\n");
619 usb_free_urb(async_urb);
620 return;
621 }
622
623 /* outbound data */
624 usb_fill_int_urb(async_urb, ir->usbdev,
625 usb_sndintpipe(ir->usbdev, ep->bEndpointAddress),
626 async_buf, size, (usb_complete_t)mce_async_callback,
627 ir, ep->bInterval);
628 memcpy(async_buf, data, size);
629
630 } else if (urb_type == MCEUSB_RX) {
631 /* standard request */
632 async_urb = ir->urb_in;
633 ir->send_flags = RECV_FLAG_IN_PROGRESS;
634
635 } else {
636 dev_err(dev, "Error! Unknown urb type %d\n", urb_type);
637 return;
638 }
639
640 dev_dbg(dev, "receive request called (size=%#x)\n", size);
641
642 async_urb->transfer_buffer_length = size;
643 async_urb->dev = ir->usbdev;
644
645 res = usb_submit_urb(async_urb, GFP_ATOMIC);
646 if (res) {
647 dev_dbg(dev, "receive request FAILED! (res=%d)\n", res);
648 return;
649 }
650 dev_dbg(dev, "receive request complete (res=%d)\n", res);
651}
652
653static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
654{
655 mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX);
656}
657
658static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
659{
660 mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX);
661}
662
663/* Send data out the IR blaster port(s) */
664static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
665{
666 struct mceusb_dev *ir = dev->priv;
667 int i, ret = 0;
668 int count, cmdcount = 0;
669 unsigned char *cmdbuf; /* MCE command buffer */
670 long signal_duration = 0; /* Singnal length in us */
671 struct timeval start_time, end_time;
672
673 do_gettimeofday(&start_time);
674
675 count = n / sizeof(int);
676
677 cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
678 if (!cmdbuf)
679 return -ENOMEM;
680
681 /* MCE tx init header */
682 cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
683 cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
684 cmdbuf[cmdcount++] = ir->tx_mask;
685
686 /* Generate mce packet data */
687 for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
688 signal_duration += txbuf[i];
689 txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
690
691 do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
692
693 /* Insert mce packet header every 4th entry */
694 if ((cmdcount < MCE_CMDBUF_SIZE) &&
695 (cmdcount - MCE_TX_HEADER_LENGTH) %
696 MCE_CODE_LENGTH == 0)
697 cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
698
699 /* Insert mce packet data */
700 if (cmdcount < MCE_CMDBUF_SIZE)
701 cmdbuf[cmdcount++] =
702 (txbuf[i] < MCE_PULSE_BIT ?
703 txbuf[i] : MCE_MAX_PULSE_LENGTH) |
704 (i & 1 ? 0x00 : MCE_PULSE_BIT);
705 else {
706 ret = -EINVAL;
707 goto out;
708 }
709
710 } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
711 (txbuf[i] -= MCE_MAX_PULSE_LENGTH));
712 }
713
714 /* Fix packet length in last header */
715 cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
716 MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) %
717 MCE_CODE_LENGTH - 1;
718
719 /* Check if we have room for the empty packet at the end */
720 if (cmdcount >= MCE_CMDBUF_SIZE) {
721 ret = -EINVAL;
722 goto out;
723 }
724
725 /* All mce commands end with an empty packet (0x80) */
726 cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
727
728 /* Transmit the command to the mce device */
729 mce_async_out(ir, cmdbuf, cmdcount);
730
731 /*
732 * The lircd gap calculation expects the write function to
733 * wait the time it takes for the ircommand to be sent before
734 * it returns.
735 */
736 do_gettimeofday(&end_time);
737 signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
738 (end_time.tv_sec - start_time.tv_sec) * 1000000;
739
740 /* delay with the closest number of ticks */
741 set_current_state(TASK_INTERRUPTIBLE);
742 schedule_timeout(usecs_to_jiffies(signal_duration));
743
744out:
745 kfree(cmdbuf);
746 return ret ? ret : n;
747}
748
749/* Sets active IR outputs -- mce devices typically have two */
750static int mceusb_set_tx_mask(struct rc_dev *dev, u32 mask)
751{
752 struct mceusb_dev *ir = dev->priv;
753
754 if (ir->flags.tx_mask_normal)
755 ir->tx_mask = mask;
756 else
757 ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
758 mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
759
760 return 0;
761}
762
763/* Sets the send carrier frequency and mode */
764static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
765{
766 struct mceusb_dev *ir = dev->priv;
767 int clk = 10000000;
768 int prescaler = 0, divisor = 0;
769 unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
770 MCE_CMD_S_CARRIER, 0x00, 0x00 };
771
772 /* Carrier has changed */
773 if (ir->carrier != carrier) {
774
775 if (carrier == 0) {
776 ir->carrier = carrier;
777 cmdbuf[2] = MCE_CMD_SIG_END;
778 cmdbuf[3] = MCE_IRDATA_TRAILER;
779 dev_dbg(ir->dev, "%s: disabling carrier "
780 "modulation\n", __func__);
781 mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
782 return carrier;
783 }
784
785 for (prescaler = 0; prescaler < 4; ++prescaler) {
786 divisor = (clk >> (2 * prescaler)) / carrier;
787 if (divisor <= 0xff) {
788 ir->carrier = carrier;
789 cmdbuf[2] = prescaler;
790 cmdbuf[3] = divisor;
791 dev_dbg(ir->dev, "%s: requesting %u HZ "
792 "carrier\n", __func__, carrier);
793
794 /* Transmit new carrier to mce device */
795 mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
796 return carrier;
797 }
798 }
799
800 return -EINVAL;
801
802 }
803
804 return carrier;
805}
806
807/*
808 * We don't do anything but print debug spew for many of the command bits
809 * we receive from the hardware, but some of them are useful information
810 * we want to store so that we can use them.
811 */
812static void mceusb_handle_command(struct mceusb_dev *ir, int index)
813{
814 u8 hi = ir->buf_in[index + 1] & 0xff;
815 u8 lo = ir->buf_in[index + 2] & 0xff;
816
817 switch (ir->buf_in[index]) {
818 /* 2-byte return value commands */
819 case MCE_CMD_S_TIMEOUT:
820 ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2);
821 break;
822
823 /* 1-byte return value commands */
824 case MCE_CMD_S_TXMASK:
825 ir->tx_mask = hi;
826 break;
827 case MCE_CMD_S_RXSENSOR:
828 ir->learning_enabled = (hi == 0x02);
829 break;
830 default:
831 break;
832 }
833}
834
835static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
836{
837 DEFINE_IR_RAW_EVENT(rawir);
838 int i = 0;
839
840 /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
841 if (ir->flags.microsoft_gen1)
842 i = 2;
843
844 /* if there's no data, just return now */
845 if (buf_len <= i)
846 return;
847
848 for (; i < buf_len; i++) {
849 switch (ir->parser_state) {
850 case SUBCMD:
851 ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
852 mceusb_dev_printdata(ir, ir->buf_in, i - 1,
853 ir->rem + 2, false);
854 mceusb_handle_command(ir, i);
855 ir->parser_state = CMD_DATA;
856 break;
857 case PARSE_IRDATA:
858 ir->rem--;
859 rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
860 rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
861 * MS_TO_NS(MCE_TIME_UNIT);
862
863 dev_dbg(ir->dev, "Storing %s with duration %d\n",
864 rawir.pulse ? "pulse" : "space",
865 rawir.duration);
866
867 ir_raw_event_store_with_filter(ir->rc, &rawir);
868 break;
869 case CMD_DATA:
870 ir->rem--;
871 break;
872 case CMD_HEADER:
873 /* decode mce packets of the form (84),AA,BB,CC,DD */
874 /* IR data packets can span USB messages - rem */
875 ir->cmd = ir->buf_in[i];
876 if ((ir->cmd == MCE_COMMAND_HEADER) ||
877 ((ir->cmd & MCE_COMMAND_MASK) !=
878 MCE_COMMAND_IRDATA)) {
879 ir->parser_state = SUBCMD;
880 continue;
881 }
882 ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
883 mceusb_dev_printdata(ir, ir->buf_in,
884 i, ir->rem + 1, false);
885 if (ir->rem)
886 ir->parser_state = PARSE_IRDATA;
887 break;
888 }
889
890 if (ir->parser_state != CMD_HEADER && !ir->rem)
891 ir->parser_state = CMD_HEADER;
892 }
893 dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
894 ir_raw_event_handle(ir->rc);
895}
896
897static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
898{
899 struct mceusb_dev *ir;
900 int buf_len;
901
902 if (!urb)
903 return;
904
905 ir = urb->context;
906 if (!ir) {
907 usb_unlink_urb(urb);
908 return;
909 }
910
911 buf_len = urb->actual_length;
912
913 if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
914 ir->send_flags = SEND_FLAG_COMPLETE;
915 dev_dbg(ir->dev, "setup answer received %d bytes\n",
916 buf_len);
917 }
918
919 switch (urb->status) {
920 /* success */
921 case 0:
922 mceusb_process_ir_data(ir, buf_len);
923 break;
924
925 case -ECONNRESET:
926 case -ENOENT:
927 case -ESHUTDOWN:
928 usb_unlink_urb(urb);
929 return;
930
931 case -EPIPE:
932 default:
933 dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
934 break;
935 }
936
937 usb_submit_urb(urb, GFP_ATOMIC);
938}
939
940static void mceusb_gen1_init(struct mceusb_dev *ir)
941{
942 int ret;
943 int maxp = ir->len_in;
944 struct device *dev = ir->dev;
945 char *data;
946
947 data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
948 if (!data) {
949 dev_err(dev, "%s: memory allocation failed!\n", __func__);
950 return;
951 }
952
953 /*
954 * This is a strange one. Windows issues a set address to the device
955 * on the receive control pipe and expect a certain value pair back
956 */
957 ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
958 USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
959 data, USB_CTRL_MSG_SZ, HZ * 3);
960 dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
961 dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
962 __func__, data[0], data[1]);
963
964 /* set feature: bit rate 38400 bps */
965 ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
966 USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
967 0xc04e, 0x0000, NULL, 0, HZ * 3);
968
969 dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
970
971 /* bRequest 4: set char length to 8 bits */
972 ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
973 4, USB_TYPE_VENDOR,
974 0x0808, 0x0000, NULL, 0, HZ * 3);
975 dev_dbg(dev, "%s - retB = %d\n", __func__, ret);
976
977 /* bRequest 2: set handshaking to use DTR/DSR */
978 ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
979 2, USB_TYPE_VENDOR,
980 0x0000, 0x0100, NULL, 0, HZ * 3);
981 dev_dbg(dev, "%s - retC = %d\n", __func__, ret);
982
983 /* device reset */
984 mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
985 mce_sync_in(ir, NULL, maxp);
986
987 /* get hw/sw revision? */
988 mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
989 mce_sync_in(ir, NULL, maxp);
990
991 kfree(data);
992};
993
994static void mceusb_gen2_init(struct mceusb_dev *ir)
995{
996 int maxp = ir->len_in;
997
998 /* device reset */
999 mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
1000 mce_sync_in(ir, NULL, maxp);
1001
1002 /* get hw/sw revision? */
1003 mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
1004 mce_sync_in(ir, NULL, maxp);
1005
1006 /* unknown what the next two actually return... */
1007 mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
1008 mce_sync_in(ir, NULL, maxp);
1009 mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
1010 mce_sync_in(ir, NULL, maxp);
1011}
1012
1013static void mceusb_get_parameters(struct mceusb_dev *ir)
1014{
1015 int maxp = ir->len_in;
1016
1017 /* get the carrier and frequency */
1018 mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
1019 mce_sync_in(ir, NULL, maxp);
1020
1021 if (!ir->flags.no_tx) {
1022 /* get the transmitter bitmask */
1023 mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
1024 mce_sync_in(ir, NULL, maxp);
1025 }
1026
1027 /* get receiver timeout value */
1028 mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
1029 mce_sync_in(ir, NULL, maxp);
1030
1031 /* get receiver sensor setting */
1032 mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
1033 mce_sync_in(ir, NULL, maxp);
1034}
1035
1036static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
1037{
1038 struct device *dev = ir->dev;
1039 struct rc_dev *rc;
1040 int ret;
1041
1042 rc = rc_allocate_device();
1043 if (!rc) {
1044 dev_err(dev, "remote dev allocation failed\n");
1045 goto out;
1046 }
1047
1048 snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
1049 mceusb_model[ir->model].name ?
1050 mceusb_model[ir->model].name :
1051 "Media Center Ed. eHome Infrared Remote Transceiver",
1052 le16_to_cpu(ir->usbdev->descriptor.idVendor),
1053 le16_to_cpu(ir->usbdev->descriptor.idProduct));
1054
1055 usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys));
1056
1057 rc->input_name = ir->name;
1058 rc->input_phys = ir->phys;
1059 usb_to_input_id(ir->usbdev, &rc->input_id);
1060 rc->dev.parent = dev;
1061 rc->priv = ir;
1062 rc->driver_type = RC_DRIVER_IR_RAW;
1063 rc->allowed_protos = RC_TYPE_ALL;
1064 rc->timeout = MS_TO_NS(1000);
1065 if (!ir->flags.no_tx) {
1066 rc->s_tx_mask = mceusb_set_tx_mask;
1067 rc->s_tx_carrier = mceusb_set_tx_carrier;
1068 rc->tx_ir = mceusb_tx_ir;
1069 }
1070 rc->driver_name = DRIVER_NAME;
1071 rc->map_name = mceusb_model[ir->model].rc_map ?
1072 mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
1073
1074 ret = rc_register_device(rc);
1075 if (ret < 0) {
1076 dev_err(dev, "remote dev registration failed\n");
1077 goto out;
1078 }
1079
1080 return rc;
1081
1082out:
1083 rc_free_device(rc);
1084 return NULL;
1085}
1086
1087static int __devinit mceusb_dev_probe(struct usb_interface *intf,
1088 const struct usb_device_id *id)
1089{
1090 struct usb_device *dev = interface_to_usbdev(intf);
1091 struct usb_host_interface *idesc;
1092 struct usb_endpoint_descriptor *ep = NULL;
1093 struct usb_endpoint_descriptor *ep_in = NULL;
1094 struct usb_endpoint_descriptor *ep_out = NULL;
1095 struct mceusb_dev *ir = NULL;
1096 int pipe, maxp, i;
1097 char buf[63], name[128] = "";
1098 enum mceusb_model_type model = id->driver_info;
1099 bool is_gen3;
1100 bool is_microsoft_gen1;
1101 bool tx_mask_normal;
1102 bool is_polaris;
1103
1104 dev_dbg(&intf->dev, "%s called\n", __func__);
1105
1106 idesc = intf->cur_altsetting;
1107
1108 is_gen3 = mceusb_model[model].mce_gen3;
1109 is_microsoft_gen1 = mceusb_model[model].mce_gen1;
1110 tx_mask_normal = mceusb_model[model].tx_mask_normal;
1111 is_polaris = mceusb_model[model].is_polaris;
1112
1113 if (is_polaris) {
1114 /* Interface 0 is IR */
1115 if (idesc->desc.bInterfaceNumber)
1116 return -ENODEV;
1117 }
1118
1119 /* step through the endpoints to find first bulk in and out endpoint */
1120 for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
1121 ep = &idesc->endpoint[i].desc;
1122
1123 if ((ep_in == NULL)
1124 && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
1125 == USB_DIR_IN)
1126 && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
1127 == USB_ENDPOINT_XFER_BULK)
1128 || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
1129 == USB_ENDPOINT_XFER_INT))) {
1130
1131 ep_in = ep;
1132 ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
1133 ep_in->bInterval = 1;
1134 dev_dbg(&intf->dev, "acceptable inbound endpoint "
1135 "found\n");
1136 }
1137
1138 if ((ep_out == NULL)
1139 && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
1140 == USB_DIR_OUT)
1141 && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
1142 == USB_ENDPOINT_XFER_BULK)
1143 || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
1144 == USB_ENDPOINT_XFER_INT))) {
1145
1146 ep_out = ep;
1147 ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
1148 ep_out->bInterval = 1;
1149 dev_dbg(&intf->dev, "acceptable outbound endpoint "
1150 "found\n");
1151 }
1152 }
1153 if (ep_in == NULL) {
1154 dev_dbg(&intf->dev, "inbound and/or endpoint not found\n");
1155 return -ENODEV;
1156 }
1157
1158 pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
1159 maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
1160
1161 ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL);
1162 if (!ir)
1163 goto mem_alloc_fail;
1164
1165 ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in);
1166 if (!ir->buf_in)
1167 goto buf_in_alloc_fail;
1168
1169 ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
1170 if (!ir->urb_in)
1171 goto urb_in_alloc_fail;
1172
1173 ir->usbdev = dev;
1174 ir->dev = &intf->dev;
1175 ir->len_in = maxp;
1176 ir->flags.microsoft_gen1 = is_microsoft_gen1;
1177 ir->flags.tx_mask_normal = tx_mask_normal;
1178 ir->flags.no_tx = mceusb_model[model].no_tx;
1179 ir->model = model;
1180
1181 /* Saving usb interface data for use by the transmitter routine */
1182 ir->usb_ep_in = ep_in;
1183 ir->usb_ep_out = ep_out;
1184
1185 if (dev->descriptor.iManufacturer
1186 && usb_string(dev, dev->descriptor.iManufacturer,
1187 buf, sizeof(buf)) > 0)
1188 strlcpy(name, buf, sizeof(name));
1189 if (dev->descriptor.iProduct
1190 && usb_string(dev, dev->descriptor.iProduct,
1191 buf, sizeof(buf)) > 0)
1192 snprintf(name + strlen(name), sizeof(name) - strlen(name),
1193 " %s", buf);
1194
1195 ir->rc = mceusb_init_rc_dev(ir);
1196 if (!ir->rc)
1197 goto rc_dev_fail;
1198
1199 /* flush buffers on the device */
1200 mce_sync_in(ir, NULL, maxp);
1201 mce_sync_in(ir, NULL, maxp);
1202
1203 /* wire up inbound data handler */
1204 usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in,
1205 maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval);
1206 ir->urb_in->transfer_dma = ir->dma_in;
1207 ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1208
1209 /* initialize device */
1210 if (ir->flags.microsoft_gen1)
1211 mceusb_gen1_init(ir);
1212 else if (!is_gen3)
1213 mceusb_gen2_init(ir);
1214
1215 mceusb_get_parameters(ir);
1216
1217 if (!ir->flags.no_tx)
1218 mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK);
1219
1220 usb_set_intfdata(intf, ir);
1221
1222 dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
1223 dev->bus->busnum, dev->devnum);
1224
1225 return 0;
1226
1227 /* Error-handling path */
1228rc_dev_fail:
1229 usb_free_urb(ir->urb_in);
1230urb_in_alloc_fail:
1231 usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
1232buf_in_alloc_fail:
1233 kfree(ir);
1234mem_alloc_fail:
1235 dev_err(&intf->dev, "%s: device setup failed!\n", __func__);
1236
1237 return -ENOMEM;
1238}
1239
1240
1241static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
1242{
1243 struct usb_device *dev = interface_to_usbdev(intf);
1244 struct mceusb_dev *ir = usb_get_intfdata(intf);
1245
1246 usb_set_intfdata(intf, NULL);
1247
1248 if (!ir)
1249 return;
1250
1251 ir->usbdev = NULL;
1252 rc_unregister_device(ir->rc);
1253 usb_kill_urb(ir->urb_in);
1254 usb_free_urb(ir->urb_in);
1255 usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
1256
1257 kfree(ir);
1258}
1259
1260static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message)
1261{
1262 struct mceusb_dev *ir = usb_get_intfdata(intf);
1263 dev_info(ir->dev, "suspend\n");
1264 usb_kill_urb(ir->urb_in);
1265 return 0;
1266}
1267
1268static int mceusb_dev_resume(struct usb_interface *intf)
1269{
1270 struct mceusb_dev *ir = usb_get_intfdata(intf);
1271 dev_info(ir->dev, "resume\n");
1272 if (usb_submit_urb(ir->urb_in, GFP_ATOMIC))
1273 return -EIO;
1274 return 0;
1275}
1276
1277static struct usb_driver mceusb_dev_driver = {
1278 .name = DRIVER_NAME,
1279 .probe = mceusb_dev_probe,
1280 .disconnect = mceusb_dev_disconnect,
1281 .suspend = mceusb_dev_suspend,
1282 .resume = mceusb_dev_resume,
1283 .reset_resume = mceusb_dev_resume,
1284 .id_table = mceusb_dev_table
1285};
1286
1287static int __init mceusb_dev_init(void)
1288{
1289 int ret;
1290
1291 ret = usb_register(&mceusb_dev_driver);
1292 if (ret < 0)
1293 printk(KERN_ERR DRIVER_NAME
1294 ": usb register failed, result = %d\n", ret);
1295
1296 return ret;
1297}
1298
1299static void __exit mceusb_dev_exit(void)
1300{
1301 usb_deregister(&mceusb_dev_driver);
1302}
1303
1304module_init(mceusb_dev_init);
1305module_exit(mceusb_dev_exit);
1306
1307MODULE_DESCRIPTION(DRIVER_DESC);
1308MODULE_AUTHOR(DRIVER_AUTHOR);
1309MODULE_LICENSE("GPL");
1310MODULE_DEVICE_TABLE(usb, mceusb_dev_table);
1311
1312module_param(debug, bool, S_IRUGO | S_IWUSR);
1313MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
new file mode 100644
index 000000000000..dd4caf8ef80b
--- /dev/null
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -0,0 +1,1244 @@
1/*
2 * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
3 *
4 * Copyright (C) 2010 Jarod Wilson <jarod@redhat.com>
5 * Copyright (C) 2009 Nuvoton PS Team
6 *
7 * Special thanks to Nuvoton for providing hardware, spec sheets and
8 * sample code upon which portions of this driver are based. Indirect
9 * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
10 * modeled after.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 * USA
26 */
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/pnp.h>
31#include <linux/io.h>
32#include <linux/interrupt.h>
33#include <linux/sched.h>
34#include <linux/slab.h>
35#include <media/rc-core.h>
36#include <linux/pci_ids.h>
37
38#include "nuvoton-cir.h"
39
40static char *chip_id = "w836x7hg";
41
42/* write val to config reg */
43static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
44{
45 outb(reg, nvt->cr_efir);
46 outb(val, nvt->cr_efdr);
47}
48
49/* read val from config reg */
50static inline u8 nvt_cr_read(struct nvt_dev *nvt, u8 reg)
51{
52 outb(reg, nvt->cr_efir);
53 return inb(nvt->cr_efdr);
54}
55
56/* update config register bit without changing other bits */
57static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
58{
59 u8 tmp = nvt_cr_read(nvt, reg) | val;
60 nvt_cr_write(nvt, tmp, reg);
61}
62
63/* clear config register bit without changing other bits */
64static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
65{
66 u8 tmp = nvt_cr_read(nvt, reg) & ~val;
67 nvt_cr_write(nvt, tmp, reg);
68}
69
70/* enter extended function mode */
71static inline void nvt_efm_enable(struct nvt_dev *nvt)
72{
73 /* Enabling Extended Function Mode explicitly requires writing 2x */
74 outb(EFER_EFM_ENABLE, nvt->cr_efir);
75 outb(EFER_EFM_ENABLE, nvt->cr_efir);
76}
77
78/* exit extended function mode */
79static inline void nvt_efm_disable(struct nvt_dev *nvt)
80{
81 outb(EFER_EFM_DISABLE, nvt->cr_efir);
82}
83
84/*
85 * When you want to address a specific logical device, write its logical
86 * device number to CR_LOGICAL_DEV_SEL, then enable/disable by writing
87 * 0x1/0x0 respectively to CR_LOGICAL_DEV_EN.
88 */
89static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev)
90{
91 outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir);
92 outb(ldev, nvt->cr_efdr);
93}
94
95/* write val to cir config register */
96static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset)
97{
98 outb(val, nvt->cir_addr + offset);
99}
100
101/* read val from cir config register */
102static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset)
103{
104 u8 val;
105
106 val = inb(nvt->cir_addr + offset);
107
108 return val;
109}
110
111/* write val to cir wake register */
112static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt,
113 u8 val, u8 offset)
114{
115 outb(val, nvt->cir_wake_addr + offset);
116}
117
118/* read val from cir wake config register */
119static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset)
120{
121 u8 val;
122
123 val = inb(nvt->cir_wake_addr + offset);
124
125 return val;
126}
127
128#define pr_reg(text, ...) \
129 printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
130
131/* dump current cir register contents */
132static void cir_dump_regs(struct nvt_dev *nvt)
133{
134 nvt_efm_enable(nvt);
135 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
136
137 pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
138 pr_reg(" * CR CIR ACTIVE : 0x%x\n",
139 nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
140 pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
141 (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
142 nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
143 pr_reg(" * CR CIR IRQ NUM: 0x%x\n",
144 nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
145
146 nvt_efm_disable(nvt);
147
148 pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
149 pr_reg(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
150 pr_reg(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
151 pr_reg(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
152 pr_reg(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
153 pr_reg(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
154 pr_reg(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
155 pr_reg(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
156 pr_reg(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
157 pr_reg(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
158 pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
159 pr_reg(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
160 pr_reg(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
161 pr_reg(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
162 pr_reg(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
163 pr_reg(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
164 pr_reg(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
165}
166
167/* dump current cir wake register contents */
168static void cir_wake_dump_regs(struct nvt_dev *nvt)
169{
170 u8 i, fifo_len;
171
172 nvt_efm_enable(nvt);
173 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
174
175 pr_reg("%s: Dump CIR WAKE logical device registers:\n",
176 NVT_DRIVER_NAME);
177 pr_reg(" * CR CIR WAKE ACTIVE : 0x%x\n",
178 nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
179 pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n",
180 (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
181 nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
182 pr_reg(" * CR CIR WAKE IRQ NUM: 0x%x\n",
183 nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
184
185 nvt_efm_disable(nvt);
186
187 pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
188 pr_reg(" * IRCON: 0x%x\n",
189 nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON));
190 pr_reg(" * IRSTS: 0x%x\n",
191 nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS));
192 pr_reg(" * IREN: 0x%x\n",
193 nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN));
194 pr_reg(" * FIFO CMP DEEP: 0x%x\n",
195 nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP));
196 pr_reg(" * FIFO CMP TOL: 0x%x\n",
197 nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL));
198 pr_reg(" * FIFO COUNT: 0x%x\n",
199 nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT));
200 pr_reg(" * SLCH: 0x%x\n",
201 nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH));
202 pr_reg(" * SLCL: 0x%x\n",
203 nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL));
204 pr_reg(" * FIFOCON: 0x%x\n",
205 nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON));
206 pr_reg(" * SRXFSTS: 0x%x\n",
207 nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS));
208 pr_reg(" * SAMPLE RX FIFO: 0x%x\n",
209 nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO));
210 pr_reg(" * WR FIFO DATA: 0x%x\n",
211 nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA));
212 pr_reg(" * RD FIFO ONLY: 0x%x\n",
213 nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
214 pr_reg(" * RD FIFO ONLY IDX: 0x%x\n",
215 nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX));
216 pr_reg(" * FIFO IGNORE: 0x%x\n",
217 nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE));
218 pr_reg(" * IRFSM: 0x%x\n",
219 nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM));
220
221 fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
222 pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
223 pr_reg("* Contents = ");
224 for (i = 0; i < fifo_len; i++)
225 printk(KERN_CONT "%02x ",
226 nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
227 printk(KERN_CONT "\n");
228}
229
230/* detect hardware features */
231static int nvt_hw_detect(struct nvt_dev *nvt)
232{
233 unsigned long flags;
234 u8 chip_major, chip_minor;
235 int ret = 0;
236
237 nvt_efm_enable(nvt);
238
239 /* Check if we're wired for the alternate EFER setup */
240 chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
241 if (chip_major == 0xff) {
242 nvt->cr_efir = CR_EFIR2;
243 nvt->cr_efdr = CR_EFDR2;
244 nvt_efm_enable(nvt);
245 chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
246 }
247
248 chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
249 nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor);
250
251 if (chip_major != CHIP_ID_HIGH ||
252 (chip_minor != CHIP_ID_LOW && chip_minor != CHIP_ID_LOW2)) {
253 nvt_pr(KERN_ERR, "%s: unsupported chip, id: 0x%02x 0x%02x",
254 chip_id, chip_major, chip_minor);
255 ret = -ENODEV;
256 }
257
258 nvt_efm_disable(nvt);
259
260 spin_lock_irqsave(&nvt->nvt_lock, flags);
261 nvt->chip_major = chip_major;
262 nvt->chip_minor = chip_minor;
263 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
264
265 return ret;
266}
267
268static void nvt_cir_ldev_init(struct nvt_dev *nvt)
269{
270 u8 val;
271
272 /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */
273 val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL);
274 val &= OUTPUT_PIN_SEL_MASK;
275 val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB);
276 nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL);
277
278 /* Select CIR logical device and enable */
279 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
280 nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
281
282 nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI);
283 nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO);
284
285 nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC);
286
287 nvt_dbg("CIR initialized, base io port address: 0x%lx, irq: %d",
288 nvt->cir_addr, nvt->cir_irq);
289}
290
291static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
292{
293 /* Select ACPI logical device, enable it and CIR Wake */
294 nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
295 nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
296
297 /* Enable CIR Wake via PSOUT# (Pin60) */
298 nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
299
300 /* enable cir interrupt of mouse/keyboard IRQ event */
301 nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
302
303 /* enable pme interrupt of cir wakeup event */
304 nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
305
306 /* Select CIR Wake logical device and enable */
307 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
308 nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
309
310 nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI);
311 nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO);
312
313 nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC);
314
315 nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d",
316 nvt->cir_wake_addr, nvt->cir_wake_irq);
317}
318
319/* clear out the hardware's cir rx fifo */
320static void nvt_clear_cir_fifo(struct nvt_dev *nvt)
321{
322 u8 val;
323
324 val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
325 nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
326}
327
328/* clear out the hardware's cir wake rx fifo */
329static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt)
330{
331 u8 val;
332
333 val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON);
334 nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR,
335 CIR_WAKE_FIFOCON);
336}
337
338/* clear out the hardware's cir tx fifo */
339static void nvt_clear_tx_fifo(struct nvt_dev *nvt)
340{
341 u8 val;
342
343 val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
344 nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON);
345}
346
347/* enable RX Trigger Level Reach and Packet End interrupts */
348static void nvt_set_cir_iren(struct nvt_dev *nvt)
349{
350 u8 iren;
351
352 iren = CIR_IREN_RTR | CIR_IREN_PE;
353 nvt_cir_reg_write(nvt, iren, CIR_IREN);
354}
355
356static void nvt_cir_regs_init(struct nvt_dev *nvt)
357{
358 /* set sample limit count (PE interrupt raised when reached) */
359 nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH);
360 nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL);
361
362 /* set fifo irq trigger levels */
363 nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV |
364 CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON);
365
366 /*
367 * Enable TX and RX, specify carrier on = low, off = high, and set
368 * sample period (currently 50us)
369 */
370 nvt_cir_reg_write(nvt,
371 CIR_IRCON_TXEN | CIR_IRCON_RXEN |
372 CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
373 CIR_IRCON);
374
375 /* clear hardware rx and tx fifos */
376 nvt_clear_cir_fifo(nvt);
377 nvt_clear_tx_fifo(nvt);
378
379 /* clear any and all stray interrupts */
380 nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
381
382 /* and finally, enable interrupts */
383 nvt_set_cir_iren(nvt);
384}
385
386static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
387{
388 /* set number of bytes needed for wake key comparison (default 67) */
389 nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_LEN, CIR_WAKE_FIFO_CMP_DEEP);
390
391 /* set tolerance/variance allowed per byte during wake compare */
392 nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE,
393 CIR_WAKE_FIFO_CMP_TOL);
394
395 /* set sample limit count (PE interrupt raised when reached) */
396 nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH);
397 nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL);
398
399 /* set cir wake fifo rx trigger level (currently 67) */
400 nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV,
401 CIR_WAKE_FIFOCON);
402
403 /*
404 * Enable TX and RX, specific carrier on = low, off = high, and set
405 * sample period (currently 50us)
406 */
407 nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
408 CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
409 CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
410 CIR_WAKE_IRCON);
411
412 /* clear cir wake rx fifo */
413 nvt_clear_cir_wake_fifo(nvt);
414
415 /* clear any and all stray interrupts */
416 nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
417}
418
419static void nvt_enable_wake(struct nvt_dev *nvt)
420{
421 nvt_efm_enable(nvt);
422
423 nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
424 nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
425 nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
426 nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
427
428 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
429 nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
430
431 nvt_efm_disable(nvt);
432
433 nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
434 CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
435 CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
436 CIR_WAKE_IRCON);
437 nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
438 nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
439}
440
441/* rx carrier detect only works in learning mode, must be called w/nvt_lock */
442static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
443{
444 u32 count, carrier, duration = 0;
445 int i;
446
447 count = nvt_cir_reg_read(nvt, CIR_FCCL) |
448 nvt_cir_reg_read(nvt, CIR_FCCH) << 8;
449
450 for (i = 0; i < nvt->pkts; i++) {
451 if (nvt->buf[i] & BUF_PULSE_BIT)
452 duration += nvt->buf[i] & BUF_LEN_MASK;
453 }
454
455 duration *= SAMPLE_PERIOD;
456
457 if (!count || !duration) {
458 nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)",
459 count, duration);
460 return 0;
461 }
462
463 carrier = (count * 1000000) / duration;
464
465 if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER))
466 nvt_dbg("WTF? Carrier frequency out of range!");
467
468 nvt_dbg("Carrier frequency: %u (count %u, duration %u)",
469 carrier, count, duration);
470
471 return carrier;
472}
473
474/*
475 * set carrier frequency
476 *
477 * set carrier on 2 registers: CP & CC
478 * always set CP as 0x81
479 * set CC by SPEC, CC = 3MHz/carrier - 1
480 */
481static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
482{
483 struct nvt_dev *nvt = dev->priv;
484 u16 val;
485
486 nvt_cir_reg_write(nvt, 1, CIR_CP);
487 val = 3000000 / (carrier) - 1;
488 nvt_cir_reg_write(nvt, val & 0xff, CIR_CC);
489
490 nvt_dbg("cp: 0x%x cc: 0x%x\n",
491 nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC));
492
493 return 0;
494}
495
496/*
497 * nvt_tx_ir
498 *
499 * 1) clean TX fifo first (handled by AP)
500 * 2) copy data from user space
501 * 3) disable RX interrupts, enable TX interrupts: TTR & TFU
502 * 4) send 9 packets to TX FIFO to open TTR
503 * in interrupt_handler:
504 * 5) send all data out
505 * go back to write():
506 * 6) disable TX interrupts, re-enable RX interupts
507 *
508 * The key problem of this function is user space data may larger than
509 * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to
510 * buf, and keep current copied data buf num in cur_buf_num. But driver's buf
511 * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
512 * set TXFCONT as 0xff, until buf_count less than 0xff.
513 */
514static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
515{
516 struct nvt_dev *nvt = dev->priv;
517 unsigned long flags;
518 size_t cur_count;
519 unsigned int i;
520 u8 iren;
521 int ret;
522
523 spin_lock_irqsave(&nvt->tx.lock, flags);
524
525 if (n >= TX_BUF_LEN) {
526 nvt->tx.buf_count = cur_count = TX_BUF_LEN;
527 ret = TX_BUF_LEN;
528 } else {
529 nvt->tx.buf_count = cur_count = n;
530 ret = n;
531 }
532
533 memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
534
535 nvt->tx.cur_buf_num = 0;
536
537 /* save currently enabled interrupts */
538 iren = nvt_cir_reg_read(nvt, CIR_IREN);
539
540 /* now disable all interrupts, save TFU & TTR */
541 nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN);
542
543 nvt->tx.tx_state = ST_TX_REPLY;
544
545 nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 |
546 CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
547
548 /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */
549 for (i = 0; i < 9; i++)
550 nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO);
551
552 spin_unlock_irqrestore(&nvt->tx.lock, flags);
553
554 wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST);
555
556 spin_lock_irqsave(&nvt->tx.lock, flags);
557 nvt->tx.tx_state = ST_TX_NONE;
558 spin_unlock_irqrestore(&nvt->tx.lock, flags);
559
560 /* restore enabled interrupts to prior state */
561 nvt_cir_reg_write(nvt, iren, CIR_IREN);
562
563 return ret;
564}
565
566/* dump contents of the last rx buffer we got from the hw rx fifo */
567static void nvt_dump_rx_buf(struct nvt_dev *nvt)
568{
569 int i;
570
571 printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts);
572 for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++)
573 printk(KERN_CONT "0x%02x ", nvt->buf[i]);
574 printk(KERN_CONT "\n");
575}
576
577/*
578 * Process raw data in rx driver buffer, store it in raw IR event kfifo,
579 * trigger decode when appropriate.
580 *
581 * We get IR data samples one byte at a time. If the msb is set, its a pulse,
582 * otherwise its a space. The lower 7 bits are the count of SAMPLE_PERIOD
583 * (default 50us) intervals for that pulse/space. A discrete signal is
584 * followed by a series of 0x7f packets, then either 0x7<something> or 0x80
585 * to signal more IR coming (repeats) or end of IR, respectively. We store
586 * sample data in the raw event kfifo until we see 0x7<something> (except f)
587 * or 0x80, at which time, we trigger a decode operation.
588 */
589static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
590{
591 DEFINE_IR_RAW_EVENT(rawir);
592 unsigned int count;
593 u32 carrier;
594 u8 sample;
595 int i;
596
597 nvt_dbg_verbose("%s firing", __func__);
598
599 if (debug)
600 nvt_dump_rx_buf(nvt);
601
602 if (nvt->carrier_detect_enabled)
603 carrier = nvt_rx_carrier_detect(nvt);
604
605 count = nvt->pkts;
606 nvt_dbg_verbose("Processing buffer of len %d", count);
607
608 init_ir_raw_event(&rawir);
609
610 for (i = 0; i < count; i++) {
611 nvt->pkts--;
612 sample = nvt->buf[i];
613
614 rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
615 rawir.duration = (sample & BUF_LEN_MASK)
616 * SAMPLE_PERIOD * 1000;
617
618 if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
619 if (nvt->rawir.pulse == rawir.pulse)
620 nvt->rawir.duration += rawir.duration;
621 else {
622 nvt->rawir.duration = rawir.duration;
623 nvt->rawir.pulse = rawir.pulse;
624 }
625 continue;
626 }
627
628 rawir.duration += nvt->rawir.duration;
629
630 init_ir_raw_event(&nvt->rawir);
631 nvt->rawir.duration = 0;
632 nvt->rawir.pulse = rawir.pulse;
633
634 if (sample == BUF_PULSE_BIT)
635 rawir.pulse = false;
636
637 if (rawir.duration) {
638 nvt_dbg("Storing %s with duration %d",
639 rawir.pulse ? "pulse" : "space",
640 rawir.duration);
641
642 ir_raw_event_store(nvt->rdev, &rawir);
643 }
644
645 /*
646 * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
647 * indicates end of IR signal, but new data incoming. In both
648 * cases, it means we're ready to call ir_raw_event_handle
649 */
650 if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
651 nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
652 ir_raw_event_handle(nvt->rdev);
653 }
654 }
655
656 nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
657 ir_raw_event_handle(nvt->rdev);
658
659 if (nvt->pkts) {
660 nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
661 nvt->pkts = 0;
662 }
663
664 nvt_dbg_verbose("%s done", __func__);
665}
666
667static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
668{
669 nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!");
670
671 nvt->pkts = 0;
672 nvt_clear_cir_fifo(nvt);
673 ir_raw_event_reset(nvt->rdev);
674}
675
676/* copy data from hardware rx fifo into driver buffer */
677static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
678{
679 unsigned long flags;
680 u8 fifocount, val;
681 unsigned int b_idx;
682 bool overrun = false;
683 int i;
684
685 /* Get count of how many bytes to read from RX FIFO */
686 fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT);
687 /* if we get 0xff, probably means the logical dev is disabled */
688 if (fifocount == 0xff)
689 return;
690 /* watch out for a fifo overrun condition */
691 else if (fifocount > RX_BUF_LEN) {
692 overrun = true;
693 fifocount = RX_BUF_LEN;
694 }
695
696 nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount);
697
698 spin_lock_irqsave(&nvt->nvt_lock, flags);
699
700 b_idx = nvt->pkts;
701
702 /* This should never happen, but lets check anyway... */
703 if (b_idx + fifocount > RX_BUF_LEN) {
704 nvt_process_rx_ir_data(nvt);
705 b_idx = 0;
706 }
707
708 /* Read fifocount bytes from CIR Sample RX FIFO register */
709 for (i = 0; i < fifocount; i++) {
710 val = nvt_cir_reg_read(nvt, CIR_SRXFIFO);
711 nvt->buf[b_idx + i] = val;
712 }
713
714 nvt->pkts += fifocount;
715 nvt_dbg("%s: pkts now %d", __func__, nvt->pkts);
716
717 nvt_process_rx_ir_data(nvt);
718
719 if (overrun)
720 nvt_handle_rx_fifo_overrun(nvt);
721
722 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
723}
724
725static void nvt_cir_log_irqs(u8 status, u8 iren)
726{
727 nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
728 status, iren,
729 status & CIR_IRSTS_RDR ? " RDR" : "",
730 status & CIR_IRSTS_RTR ? " RTR" : "",
731 status & CIR_IRSTS_PE ? " PE" : "",
732 status & CIR_IRSTS_RFO ? " RFO" : "",
733 status & CIR_IRSTS_TE ? " TE" : "",
734 status & CIR_IRSTS_TTR ? " TTR" : "",
735 status & CIR_IRSTS_TFU ? " TFU" : "",
736 status & CIR_IRSTS_GH ? " GH" : "",
737 status & ~(CIR_IRSTS_RDR | CIR_IRSTS_RTR | CIR_IRSTS_PE |
738 CIR_IRSTS_RFO | CIR_IRSTS_TE | CIR_IRSTS_TTR |
739 CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : "");
740}
741
742static bool nvt_cir_tx_inactive(struct nvt_dev *nvt)
743{
744 unsigned long flags;
745 bool tx_inactive;
746 u8 tx_state;
747
748 spin_lock_irqsave(&nvt->tx.lock, flags);
749 tx_state = nvt->tx.tx_state;
750 spin_unlock_irqrestore(&nvt->tx.lock, flags);
751
752 tx_inactive = (tx_state == ST_TX_NONE);
753
754 return tx_inactive;
755}
756
757/* interrupt service routine for incoming and outgoing CIR data */
758static irqreturn_t nvt_cir_isr(int irq, void *data)
759{
760 struct nvt_dev *nvt = data;
761 u8 status, iren, cur_state;
762 unsigned long flags;
763
764 nvt_dbg_verbose("%s firing", __func__);
765
766 nvt_efm_enable(nvt);
767 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
768 nvt_efm_disable(nvt);
769
770 /*
771 * Get IR Status register contents. Write 1 to ack/clear
772 *
773 * bit: reg name - description
774 * 7: CIR_IRSTS_RDR - RX Data Ready
775 * 6: CIR_IRSTS_RTR - RX FIFO Trigger Level Reach
776 * 5: CIR_IRSTS_PE - Packet End
777 * 4: CIR_IRSTS_RFO - RX FIFO Overrun (RDR will also be set)
778 * 3: CIR_IRSTS_TE - TX FIFO Empty
779 * 2: CIR_IRSTS_TTR - TX FIFO Trigger Level Reach
780 * 1: CIR_IRSTS_TFU - TX FIFO Underrun
781 * 0: CIR_IRSTS_GH - Min Length Detected
782 */
783 status = nvt_cir_reg_read(nvt, CIR_IRSTS);
784 if (!status) {
785 nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
786 nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
787 return IRQ_RETVAL(IRQ_NONE);
788 }
789
790 /* ack/clear all irq flags we've got */
791 nvt_cir_reg_write(nvt, status, CIR_IRSTS);
792 nvt_cir_reg_write(nvt, 0, CIR_IRSTS);
793
794 /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */
795 iren = nvt_cir_reg_read(nvt, CIR_IREN);
796 if (!iren) {
797 nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
798 return IRQ_RETVAL(IRQ_NONE);
799 }
800
801 if (debug)
802 nvt_cir_log_irqs(status, iren);
803
804 if (status & CIR_IRSTS_RTR) {
805 /* FIXME: add code for study/learn mode */
806 /* We only do rx if not tx'ing */
807 if (nvt_cir_tx_inactive(nvt))
808 nvt_get_rx_ir_data(nvt);
809 }
810
811 if (status & CIR_IRSTS_PE) {
812 if (nvt_cir_tx_inactive(nvt))
813 nvt_get_rx_ir_data(nvt);
814
815 spin_lock_irqsave(&nvt->nvt_lock, flags);
816
817 cur_state = nvt->study_state;
818
819 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
820
821 if (cur_state == ST_STUDY_NONE)
822 nvt_clear_cir_fifo(nvt);
823 }
824
825 if (status & CIR_IRSTS_TE)
826 nvt_clear_tx_fifo(nvt);
827
828 if (status & CIR_IRSTS_TTR) {
829 unsigned int pos, count;
830 u8 tmp;
831
832 spin_lock_irqsave(&nvt->tx.lock, flags);
833
834 pos = nvt->tx.cur_buf_num;
835 count = nvt->tx.buf_count;
836
837 /* Write data into the hardware tx fifo while pos < count */
838 if (pos < count) {
839 nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO);
840 nvt->tx.cur_buf_num++;
841 /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */
842 } else {
843 tmp = nvt_cir_reg_read(nvt, CIR_IREN);
844 nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
845 }
846
847 spin_unlock_irqrestore(&nvt->tx.lock, flags);
848
849 }
850
851 if (status & CIR_IRSTS_TFU) {
852 spin_lock_irqsave(&nvt->tx.lock, flags);
853 if (nvt->tx.tx_state == ST_TX_REPLY) {
854 nvt->tx.tx_state = ST_TX_REQUEST;
855 wake_up(&nvt->tx.queue);
856 }
857 spin_unlock_irqrestore(&nvt->tx.lock, flags);
858 }
859
860 nvt_dbg_verbose("%s done", __func__);
861 return IRQ_RETVAL(IRQ_HANDLED);
862}
863
864/* Interrupt service routine for CIR Wake */
865static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
866{
867 u8 status, iren, val;
868 struct nvt_dev *nvt = data;
869 unsigned long flags;
870
871 nvt_dbg_wake("%s firing", __func__);
872
873 status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
874 if (!status)
875 return IRQ_RETVAL(IRQ_NONE);
876
877 if (status & CIR_WAKE_IRSTS_IR_PENDING)
878 nvt_clear_cir_wake_fifo(nvt);
879
880 nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS);
881 nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS);
882
883 /* Interrupt may be shared with CIR, bail if Wake not enabled */
884 iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
885 if (!iren) {
886 nvt_dbg_wake("%s exiting, wake not enabled", __func__);
887 return IRQ_RETVAL(IRQ_HANDLED);
888 }
889
890 if ((status & CIR_WAKE_IRSTS_PE) &&
891 (nvt->wake_state == ST_WAKE_START)) {
892 while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) {
893 val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
894 nvt_dbg("setting wake up key: 0x%x", val);
895 }
896
897 nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
898 spin_lock_irqsave(&nvt->nvt_lock, flags);
899 nvt->wake_state = ST_WAKE_FINISH;
900 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
901 }
902
903 nvt_dbg_wake("%s done", __func__);
904 return IRQ_RETVAL(IRQ_HANDLED);
905}
906
907static void nvt_enable_cir(struct nvt_dev *nvt)
908{
909 /* set function enable flags */
910 nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN |
911 CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
912 CIR_IRCON);
913
914 nvt_efm_enable(nvt);
915
916 /* enable the CIR logical device */
917 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
918 nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
919
920 nvt_efm_disable(nvt);
921
922 /* clear all pending interrupts */
923 nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
924
925 /* enable interrupts */
926 nvt_set_cir_iren(nvt);
927}
928
929static void nvt_disable_cir(struct nvt_dev *nvt)
930{
931 /* disable CIR interrupts */
932 nvt_cir_reg_write(nvt, 0, CIR_IREN);
933
934 /* clear any and all pending interrupts */
935 nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
936
937 /* clear all function enable flags */
938 nvt_cir_reg_write(nvt, 0, CIR_IRCON);
939
940 /* clear hardware rx and tx fifos */
941 nvt_clear_cir_fifo(nvt);
942 nvt_clear_tx_fifo(nvt);
943
944 nvt_efm_enable(nvt);
945
946 /* disable the CIR logical device */
947 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
948 nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
949
950 nvt_efm_disable(nvt);
951}
952
953static int nvt_open(struct rc_dev *dev)
954{
955 struct nvt_dev *nvt = dev->priv;
956 unsigned long flags;
957
958 spin_lock_irqsave(&nvt->nvt_lock, flags);
959 nvt->in_use = true;
960 nvt_enable_cir(nvt);
961 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
962
963 return 0;
964}
965
966static void nvt_close(struct rc_dev *dev)
967{
968 struct nvt_dev *nvt = dev->priv;
969 unsigned long flags;
970
971 spin_lock_irqsave(&nvt->nvt_lock, flags);
972 nvt->in_use = false;
973 nvt_disable_cir(nvt);
974 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
975}
976
977/* Allocate memory, probe hardware, and initialize everything */
978static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
979{
980 struct nvt_dev *nvt;
981 struct rc_dev *rdev;
982 int ret = -ENOMEM;
983
984 nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
985 if (!nvt)
986 return ret;
987
988 /* input device for IR remote (and tx) */
989 rdev = rc_allocate_device();
990 if (!rdev)
991 goto failure;
992
993 ret = -ENODEV;
994 /* validate pnp resources */
995 if (!pnp_port_valid(pdev, 0) ||
996 pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) {
997 dev_err(&pdev->dev, "IR PNP Port not valid!\n");
998 goto failure;
999 }
1000
1001 if (!pnp_irq_valid(pdev, 0)) {
1002 dev_err(&pdev->dev, "PNP IRQ not valid!\n");
1003 goto failure;
1004 }
1005
1006 if (!pnp_port_valid(pdev, 1) ||
1007 pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) {
1008 dev_err(&pdev->dev, "Wake PNP Port not valid!\n");
1009 goto failure;
1010 }
1011
1012 nvt->cir_addr = pnp_port_start(pdev, 0);
1013 nvt->cir_irq = pnp_irq(pdev, 0);
1014
1015 nvt->cir_wake_addr = pnp_port_start(pdev, 1);
1016 /* irq is always shared between cir and cir wake */
1017 nvt->cir_wake_irq = nvt->cir_irq;
1018
1019 nvt->cr_efir = CR_EFIR;
1020 nvt->cr_efdr = CR_EFDR;
1021
1022 spin_lock_init(&nvt->nvt_lock);
1023 spin_lock_init(&nvt->tx.lock);
1024 init_ir_raw_event(&nvt->rawir);
1025
1026 ret = -EBUSY;
1027 /* now claim resources */
1028 if (!request_region(nvt->cir_addr,
1029 CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
1030 goto failure;
1031
1032 if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
1033 NVT_DRIVER_NAME, (void *)nvt))
1034 goto failure;
1035
1036 if (!request_region(nvt->cir_wake_addr,
1037 CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
1038 goto failure;
1039
1040 if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
1041 NVT_DRIVER_NAME, (void *)nvt))
1042 goto failure;
1043
1044 pnp_set_drvdata(pdev, nvt);
1045 nvt->pdev = pdev;
1046
1047 init_waitqueue_head(&nvt->tx.queue);
1048
1049 ret = nvt_hw_detect(nvt);
1050 if (ret)
1051 goto failure;
1052
1053 /* Initialize CIR & CIR Wake Logical Devices */
1054 nvt_efm_enable(nvt);
1055 nvt_cir_ldev_init(nvt);
1056 nvt_cir_wake_ldev_init(nvt);
1057 nvt_efm_disable(nvt);
1058
1059 /* Initialize CIR & CIR Wake Config Registers */
1060 nvt_cir_regs_init(nvt);
1061 nvt_cir_wake_regs_init(nvt);
1062
1063 /* Set up the rc device */
1064 rdev->priv = nvt;
1065 rdev->driver_type = RC_DRIVER_IR_RAW;
1066 rdev->allowed_protos = RC_TYPE_ALL;
1067 rdev->open = nvt_open;
1068 rdev->close = nvt_close;
1069 rdev->tx_ir = nvt_tx_ir;
1070 rdev->s_tx_carrier = nvt_set_tx_carrier;
1071 rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
1072 rdev->input_id.bustype = BUS_HOST;
1073 rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2;
1074 rdev->input_id.product = nvt->chip_major;
1075 rdev->input_id.version = nvt->chip_minor;
1076 rdev->driver_name = NVT_DRIVER_NAME;
1077 rdev->map_name = RC_MAP_RC6_MCE;
1078#if 0
1079 rdev->min_timeout = XYZ;
1080 rdev->max_timeout = XYZ;
1081 rdev->timeout = XYZ;
1082 /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
1083 rdev->rx_resolution = XYZ;
1084 /* tx bits */
1085 rdev->tx_resolution = XYZ;
1086#endif
1087
1088 ret = rc_register_device(rdev);
1089 if (ret)
1090 goto failure;
1091
1092 device_set_wakeup_capable(&pdev->dev, 1);
1093 device_set_wakeup_enable(&pdev->dev, 1);
1094 nvt->rdev = rdev;
1095 nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
1096 if (debug) {
1097 cir_dump_regs(nvt);
1098 cir_wake_dump_regs(nvt);
1099 }
1100
1101 return 0;
1102
1103failure:
1104 if (nvt->cir_irq)
1105 free_irq(nvt->cir_irq, nvt);
1106 if (nvt->cir_addr)
1107 release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
1108
1109 if (nvt->cir_wake_irq)
1110 free_irq(nvt->cir_wake_irq, nvt);
1111 if (nvt->cir_wake_addr)
1112 release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
1113
1114 rc_free_device(rdev);
1115 kfree(nvt);
1116
1117 return ret;
1118}
1119
1120static void __devexit nvt_remove(struct pnp_dev *pdev)
1121{
1122 struct nvt_dev *nvt = pnp_get_drvdata(pdev);
1123 unsigned long flags;
1124
1125 spin_lock_irqsave(&nvt->nvt_lock, flags);
1126 /* disable CIR */
1127 nvt_cir_reg_write(nvt, 0, CIR_IREN);
1128 nvt_disable_cir(nvt);
1129 /* enable CIR Wake (for IR power-on) */
1130 nvt_enable_wake(nvt);
1131 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
1132
1133 /* free resources */
1134 free_irq(nvt->cir_irq, nvt);
1135 free_irq(nvt->cir_wake_irq, nvt);
1136 release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
1137 release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
1138
1139 rc_unregister_device(nvt->rdev);
1140
1141 kfree(nvt);
1142}
1143
1144static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
1145{
1146 struct nvt_dev *nvt = pnp_get_drvdata(pdev);
1147 unsigned long flags;
1148
1149 nvt_dbg("%s called", __func__);
1150
1151 /* zero out misc state tracking */
1152 spin_lock_irqsave(&nvt->nvt_lock, flags);
1153 nvt->study_state = ST_STUDY_NONE;
1154 nvt->wake_state = ST_WAKE_NONE;
1155 spin_unlock_irqrestore(&nvt->nvt_lock, flags);
1156
1157 spin_lock_irqsave(&nvt->tx.lock, flags);
1158 nvt->tx.tx_state = ST_TX_NONE;
1159 spin_unlock_irqrestore(&nvt->tx.lock, flags);
1160
1161 /* disable all CIR interrupts */
1162 nvt_cir_reg_write(nvt, 0, CIR_IREN);
1163
1164 nvt_efm_enable(nvt);
1165
1166 /* disable cir logical dev */
1167 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
1168 nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
1169
1170 nvt_efm_disable(nvt);
1171
1172 /* make sure wake is enabled */
1173 nvt_enable_wake(nvt);
1174
1175 return 0;
1176}
1177
1178static int nvt_resume(struct pnp_dev *pdev)
1179{
1180 int ret = 0;
1181 struct nvt_dev *nvt = pnp_get_drvdata(pdev);
1182
1183 nvt_dbg("%s called", __func__);
1184
1185 /* open interrupt */
1186 nvt_set_cir_iren(nvt);
1187
1188 /* Enable CIR logical device */
1189 nvt_efm_enable(nvt);
1190 nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
1191 nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
1192
1193 nvt_efm_disable(nvt);
1194
1195 nvt_cir_regs_init(nvt);
1196 nvt_cir_wake_regs_init(nvt);
1197
1198 return ret;
1199}
1200
1201static void nvt_shutdown(struct pnp_dev *pdev)
1202{
1203 struct nvt_dev *nvt = pnp_get_drvdata(pdev);
1204 nvt_enable_wake(nvt);
1205}
1206
1207static const struct pnp_device_id nvt_ids[] = {
1208 { "WEC0530", 0 }, /* CIR */
1209 { "NTN0530", 0 }, /* CIR for new chip's pnp id*/
1210 { "", 0 },
1211};
1212
1213static struct pnp_driver nvt_driver = {
1214 .name = NVT_DRIVER_NAME,
1215 .id_table = nvt_ids,
1216 .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
1217 .probe = nvt_probe,
1218 .remove = __devexit_p(nvt_remove),
1219 .suspend = nvt_suspend,
1220 .resume = nvt_resume,
1221 .shutdown = nvt_shutdown,
1222};
1223
1224int nvt_init(void)
1225{
1226 return pnp_register_driver(&nvt_driver);
1227}
1228
1229void nvt_exit(void)
1230{
1231 pnp_unregister_driver(&nvt_driver);
1232}
1233
1234module_param(debug, int, S_IRUGO | S_IWUSR);
1235MODULE_PARM_DESC(debug, "Enable debugging output");
1236
1237MODULE_DEVICE_TABLE(pnp, nvt_ids);
1238MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver");
1239
1240MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
1241MODULE_LICENSE("GPL");
1242
1243module_init(nvt_init);
1244module_exit(nvt_exit);
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
new file mode 100644
index 000000000000..1df82351cb03
--- /dev/null
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -0,0 +1,407 @@
1/*
2 * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
3 *
4 * Copyright (C) 2010 Jarod Wilson <jarod@redhat.com>
5 * Copyright (C) 2009 Nuvoton PS Team
6 *
7 * Special thanks to Nuvoton for providing hardware, spec sheets and
8 * sample code upon which portions of this driver are based. Indirect
9 * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
10 * modeled after.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 * USA
26 */
27
28#include <linux/spinlock.h>
29#include <linux/ioctl.h>
30
31/* platform driver name to register */
32#define NVT_DRIVER_NAME "nuvoton-cir"
33
34/* debugging module parameter */
35static int debug;
36
37
38#define nvt_pr(level, text, ...) \
39 printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
40
41#define nvt_dbg(text, ...) \
42 if (debug) \
43 printk(KERN_DEBUG \
44 KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
45
46#define nvt_dbg_verbose(text, ...) \
47 if (debug > 1) \
48 printk(KERN_DEBUG \
49 KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
50
51#define nvt_dbg_wake(text, ...) \
52 if (debug > 2) \
53 printk(KERN_DEBUG \
54 KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
55
56
57/*
58 * Original lirc driver said min value of 76, and recommended value of 256
59 * for the buffer length, but then used 2048. Never mind that the size of the
60 * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm
61 * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes),
62 * and I don't have TX-capable hardware to test/debug on...
63 */
64#define TX_BUF_LEN 256
65#define RX_BUF_LEN 32
66
67struct nvt_dev {
68 struct pnp_dev *pdev;
69 struct rc_dev *rdev;
70 struct ir_raw_event rawir;
71
72 spinlock_t nvt_lock;
73 bool in_use;
74
75 /* for rx */
76 u8 buf[RX_BUF_LEN];
77 unsigned int pkts;
78
79 struct {
80 spinlock_t lock;
81 u8 buf[TX_BUF_LEN];
82 unsigned int buf_count;
83 unsigned int cur_buf_num;
84 wait_queue_head_t queue;
85 u8 tx_state;
86 } tx;
87
88 /* EFER Config register index/data pair */
89 u8 cr_efir;
90 u8 cr_efdr;
91
92 /* hardware I/O settings */
93 unsigned long cir_addr;
94 unsigned long cir_wake_addr;
95 int cir_irq;
96 int cir_wake_irq;
97
98 /* hardware id */
99 u8 chip_major;
100 u8 chip_minor;
101
102 /* hardware features */
103 bool hw_learning_capable;
104 bool hw_tx_capable;
105
106 /* rx settings */
107 bool learning_enabled;
108 bool carrier_detect_enabled;
109
110 /* track cir wake state */
111 u8 wake_state;
112 /* for study */
113 u8 study_state;
114 /* carrier period = 1 / frequency */
115 u32 carrier;
116};
117
118/* study states */
119#define ST_STUDY_NONE 0x0
120#define ST_STUDY_START 0x1
121#define ST_STUDY_CARRIER 0x2
122#define ST_STUDY_ALL_RECV 0x4
123
124/* wake states */
125#define ST_WAKE_NONE 0x0
126#define ST_WAKE_START 0x1
127#define ST_WAKE_FINISH 0x2
128
129/* receive states */
130#define ST_RX_WAIT_7F 0x1
131#define ST_RX_WAIT_HEAD 0x2
132#define ST_RX_WAIT_SILENT_END 0x4
133
134/* send states */
135#define ST_TX_NONE 0x0
136#define ST_TX_REQUEST 0x2
137#define ST_TX_REPLY 0x4
138
139/* buffer packet constants */
140#define BUF_PULSE_BIT 0x80
141#define BUF_LEN_MASK 0x7f
142#define BUF_REPEAT_BYTE 0x70
143#define BUF_REPEAT_MASK 0xf0
144
145/* CIR settings */
146
147/* total length of CIR and CIR WAKE */
148#define CIR_IOREG_LENGTH 0x0f
149
150/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */
151#define CIR_RX_LIMIT_COUNT 0x7d0
152
153/* CIR Regs */
154#define CIR_IRCON 0x00
155#define CIR_IRSTS 0x01
156#define CIR_IREN 0x02
157#define CIR_RXFCONT 0x03
158#define CIR_CP 0x04
159#define CIR_CC 0x05
160#define CIR_SLCH 0x06
161#define CIR_SLCL 0x07
162#define CIR_FIFOCON 0x08
163#define CIR_IRFIFOSTS 0x09
164#define CIR_SRXFIFO 0x0a
165#define CIR_TXFCONT 0x0b
166#define CIR_STXFIFO 0x0c
167#define CIR_FCCH 0x0d
168#define CIR_FCCL 0x0e
169#define CIR_IRFSM 0x0f
170
171/* CIR IRCON settings */
172#define CIR_IRCON_RECV 0x80
173#define CIR_IRCON_WIREN 0x40
174#define CIR_IRCON_TXEN 0x20
175#define CIR_IRCON_RXEN 0x10
176#define CIR_IRCON_WRXINV 0x08
177#define CIR_IRCON_RXINV 0x04
178
179#define CIR_IRCON_SAMPLE_PERIOD_SEL_1 0x00
180#define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01
181#define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02
182#define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03
183
184/* FIXME: make this a runtime option */
185/* select sample period as 50us */
186#define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
187
188/* CIR IRSTS settings */
189#define CIR_IRSTS_RDR 0x80
190#define CIR_IRSTS_RTR 0x40
191#define CIR_IRSTS_PE 0x20
192#define CIR_IRSTS_RFO 0x10
193#define CIR_IRSTS_TE 0x08
194#define CIR_IRSTS_TTR 0x04
195#define CIR_IRSTS_TFU 0x02
196#define CIR_IRSTS_GH 0x01
197
198/* CIR IREN settings */
199#define CIR_IREN_RDR 0x80
200#define CIR_IREN_RTR 0x40
201#define CIR_IREN_PE 0x20
202#define CIR_IREN_RFO 0x10
203#define CIR_IREN_TE 0x08
204#define CIR_IREN_TTR 0x04
205#define CIR_IREN_TFU 0x02
206#define CIR_IREN_GH 0x01
207
208/* CIR FIFOCON settings */
209#define CIR_FIFOCON_TXFIFOCLR 0x80
210
211#define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00
212#define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10
213#define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20
214#define CIR_FIFOCON_TX_TRIGGER_LEV_8 0x30
215
216/* FIXME: make this a runtime option */
217/* select TX trigger level as 16 */
218#define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16
219
220#define CIR_FIFOCON_RXFIFOCLR 0x08
221
222#define CIR_FIFOCON_RX_TRIGGER_LEV_1 0x00
223#define CIR_FIFOCON_RX_TRIGGER_LEV_8 0x01
224#define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02
225#define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03
226
227/* FIXME: make this a runtime option */
228/* select RX trigger level as 24 */
229#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_24
230
231/* CIR IRFIFOSTS settings */
232#define CIR_IRFIFOSTS_IR_PENDING 0x80
233#define CIR_IRFIFOSTS_RX_GS 0x40
234#define CIR_IRFIFOSTS_RX_FTA 0x20
235#define CIR_IRFIFOSTS_RX_EMPTY 0x10
236#define CIR_IRFIFOSTS_RX_FULL 0x08
237#define CIR_IRFIFOSTS_TX_FTA 0x04
238#define CIR_IRFIFOSTS_TX_EMPTY 0x02
239#define CIR_IRFIFOSTS_TX_FULL 0x01
240
241
242/* CIR WAKE UP Regs */
243#define CIR_WAKE_IRCON 0x00
244#define CIR_WAKE_IRSTS 0x01
245#define CIR_WAKE_IREN 0x02
246#define CIR_WAKE_FIFO_CMP_DEEP 0x03
247#define CIR_WAKE_FIFO_CMP_TOL 0x04
248#define CIR_WAKE_FIFO_COUNT 0x05
249#define CIR_WAKE_SLCH 0x06
250#define CIR_WAKE_SLCL 0x07
251#define CIR_WAKE_FIFOCON 0x08
252#define CIR_WAKE_SRXFSTS 0x09
253#define CIR_WAKE_SAMPLE_RX_FIFO 0x0a
254#define CIR_WAKE_WR_FIFO_DATA 0x0b
255#define CIR_WAKE_RD_FIFO_ONLY 0x0c
256#define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0d
257#define CIR_WAKE_FIFO_IGNORE 0x0e
258#define CIR_WAKE_IRFSM 0x0f
259
260/* CIR WAKE UP IRCON settings */
261#define CIR_WAKE_IRCON_DEC_RST 0x80
262#define CIR_WAKE_IRCON_MODE1 0x40
263#define CIR_WAKE_IRCON_MODE0 0x20
264#define CIR_WAKE_IRCON_RXEN 0x10
265#define CIR_WAKE_IRCON_R 0x08
266#define CIR_WAKE_IRCON_RXINV 0x04
267
268/* FIXME/jarod: make this a runtime option */
269/* select a same sample period like cir register */
270#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
271
272/* CIR WAKE IRSTS Bits */
273#define CIR_WAKE_IRSTS_RDR 0x80
274#define CIR_WAKE_IRSTS_RTR 0x40
275#define CIR_WAKE_IRSTS_PE 0x20
276#define CIR_WAKE_IRSTS_RFO 0x10
277#define CIR_WAKE_IRSTS_GH 0x08
278#define CIR_WAKE_IRSTS_IR_PENDING 0x01
279
280/* CIR WAKE UP IREN Bits */
281#define CIR_WAKE_IREN_RDR 0x80
282#define CIR_WAKE_IREN_RTR 0x40
283#define CIR_WAKE_IREN_PE 0x20
284#define CIR_WAKE_IREN_RFO 0x10
285#define CIR_WAKE_IREN_TE 0x08
286#define CIR_WAKE_IREN_TTR 0x04
287#define CIR_WAKE_IREN_TFU 0x02
288#define CIR_WAKE_IREN_GH 0x01
289
290/* CIR WAKE FIFOCON settings */
291#define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08
292
293#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00
294#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01
295#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02
296#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03
297
298/* FIXME: make this a runtime option */
299/* select WAKE UP RX trigger level as 67 */
300#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67
301
302/* CIR WAKE SRXFSTS settings */
303#define CIR_WAKE_IRFIFOSTS_RX_GS 0x80
304#define CIR_WAKE_IRFIFOSTS_RX_FTA 0x40
305#define CIR_WAKE_IRFIFOSTS_RX_EMPTY 0x20
306#define CIR_WAKE_IRFIFOSTS_RX_FULL 0x10
307
308/* CIR Wake FIFO buffer is 67 bytes long */
309#define CIR_WAKE_FIFO_LEN 67
310/* CIR Wake byte comparison tolerance */
311#define CIR_WAKE_CMP_TOLERANCE 5
312
313/*
314 * Extended Function Enable Registers:
315 * Extended Function Index Register
316 * Extended Function Data Register
317 */
318#define CR_EFIR 0x2e
319#define CR_EFDR 0x2f
320
321/* Possible alternate EFER values, depends on how the chip is wired */
322#define CR_EFIR2 0x4e
323#define CR_EFDR2 0x4f
324
325/* Extended Function Mode enable/disable magic values */
326#define EFER_EFM_ENABLE 0x87
327#define EFER_EFM_DISABLE 0xaa
328
329/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
330#define CHIP_ID_HIGH 0xb4
331#define CHIP_ID_LOW 0x72
332#define CHIP_ID_LOW2 0x73
333
334/* Config regs we need to care about */
335#define CR_SOFTWARE_RESET 0x02
336#define CR_LOGICAL_DEV_SEL 0x07
337#define CR_CHIP_ID_HI 0x20
338#define CR_CHIP_ID_LO 0x21
339#define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */
340#define CR_OUTPUT_PIN_SEL 0x27
341#define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */
342/* next three regs valid for both the CIR and CIR_WAKE logical devices */
343#define CR_CIR_BASE_ADDR_HI 0x60
344#define CR_CIR_BASE_ADDR_LO 0x61
345#define CR_CIR_IRQ_RSRC 0x70
346/* next three regs valid only for ACPI logical dev */
347#define CR_ACPI_CIR_WAKE 0xe0
348#define CR_ACPI_IRQ_EVENTS 0xf6
349#define CR_ACPI_IRQ_EVENTS2 0xf7
350
351/* Logical devices that we need to care about */
352#define LOGICAL_DEV_LPT 0x01
353#define LOGICAL_DEV_CIR 0x06
354#define LOGICAL_DEV_ACPI 0x0a
355#define LOGICAL_DEV_CIR_WAKE 0x0e
356
357#define LOGICAL_DEV_DISABLE 0x00
358#define LOGICAL_DEV_ENABLE 0x01
359
360#define CIR_WAKE_ENABLE_BIT 0x08
361#define CIR_INTR_MOUSE_IRQ_BIT 0x80
362#define PME_INTR_CIR_PASS_BIT 0x08
363
364#define OUTPUT_PIN_SEL_MASK 0xbc
365#define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */
366#define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */
367
368/* MCE CIR signal length, related on sample period */
369
370/* MCE CIR controller signal length: about 43ms
371 * 43ms / 50us (sample period) * 0.85 (inaccuracy)
372 */
373#define CONTROLLER_BUF_LEN_MIN 830
374
375/* MCE CIR keyboard signal length: about 26ms
376 * 26ms / 50us (sample period) * 0.85 (inaccuracy)
377 */
378#define KEYBOARD_BUF_LEN_MAX 650
379#define KEYBOARD_BUF_LEN_MIN 610
380
381/* MCE CIR mouse signal length: about 24ms
382 * 24ms / 50us (sample period) * 0.85 (inaccuracy)
383 */
384#define MOUSE_BUF_LEN_MIN 565
385
386#define CIR_SAMPLE_PERIOD 50
387#define CIR_SAMPLE_LOW_INACCURACY 0.85
388
389/* MAX silence time that driver will sent to lirc */
390#define MAX_SILENCE_TIME 60000
391
392#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100
393#define SAMPLE_PERIOD 100
394
395#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50
396#define SAMPLE_PERIOD 50
397
398#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25
399#define SAMPLE_PERIOD 25
400
401#else
402#define SAMPLE_PERIOD 1
403#endif
404
405/* as VISTA MCE definition, valid carrier value */
406#define MAX_CARRIER 60000
407#define MIN_CARRIER 30000
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
new file mode 100644
index 000000000000..873b38789751
--- /dev/null
+++ b/drivers/media/rc/rc-core-priv.h
@@ -0,0 +1,193 @@
1/*
2 * Remote Controller core raw events header
3 *
4 * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#ifndef _RC_CORE_PRIV
17#define _RC_CORE_PRIV
18
19#include <linux/slab.h>
20#include <linux/spinlock.h>
21#include <media/rc-core.h>
22
23struct ir_raw_handler {
24 struct list_head list;
25
26 u64 protocols; /* which are handled by this handler */
27 int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
28
29 /* These two should only be used by the lirc decoder */
30 int (*raw_register)(struct rc_dev *dev);
31 int (*raw_unregister)(struct rc_dev *dev);
32};
33
34struct ir_raw_event_ctrl {
35 struct list_head list; /* to keep track of raw clients */
36 struct task_struct *thread;
37 spinlock_t lock;
38 struct kfifo kfifo; /* fifo for the pulse/space durations */
39 ktime_t last_event; /* when last event occurred */
40 enum raw_event_type last_type; /* last event type */
41 struct rc_dev *dev; /* pointer to the parent rc_dev */
42 u64 enabled_protocols; /* enabled raw protocol decoders */
43
44 /* raw decoder state follows */
45 struct ir_raw_event prev_ev;
46 struct ir_raw_event this_ev;
47 struct nec_dec {
48 int state;
49 unsigned count;
50 u32 bits;
51 bool is_nec_x;
52 bool necx_repeat;
53 } nec;
54 struct rc5_dec {
55 int state;
56 u32 bits;
57 unsigned count;
58 unsigned wanted_bits;
59 } rc5;
60 struct rc6_dec {
61 int state;
62 u8 header;
63 u32 body;
64 bool toggle;
65 unsigned count;
66 unsigned wanted_bits;
67 } rc6;
68 struct sony_dec {
69 int state;
70 u32 bits;
71 unsigned count;
72 } sony;
73 struct jvc_dec {
74 int state;
75 u16 bits;
76 u16 old_bits;
77 unsigned count;
78 bool first;
79 bool toggle;
80 } jvc;
81 struct rc5_sz_dec {
82 int state;
83 u32 bits;
84 unsigned count;
85 unsigned wanted_bits;
86 } rc5_sz;
87 struct lirc_codec {
88 struct rc_dev *dev;
89 struct lirc_driver *drv;
90 int carrier_low;
91
92 ktime_t gap_start;
93 u64 gap_duration;
94 bool gap;
95 bool send_timeout_reports;
96
97 } lirc;
98};
99
100/* macros for IR decoders */
101static inline bool geq_margin(unsigned d1, unsigned d2, unsigned margin)
102{
103 return d1 > (d2 - margin);
104}
105
106static inline bool eq_margin(unsigned d1, unsigned d2, unsigned margin)
107{
108 return ((d1 > (d2 - margin)) && (d1 < (d2 + margin)));
109}
110
111static inline bool is_transition(struct ir_raw_event *x, struct ir_raw_event *y)
112{
113 return x->pulse != y->pulse;
114}
115
116static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
117{
118 if (duration > ev->duration)
119 ev->duration = 0;
120 else
121 ev->duration -= duration;
122}
123
124/* Returns true if event is normal pulse/space event */
125static inline bool is_timing_event(struct ir_raw_event ev)
126{
127 return !ev.carrier_report && !ev.reset;
128}
129
130#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
131#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
132
133/*
134 * Routines from rc-raw.c to be used internally and by decoders
135 */
136u64 ir_raw_get_allowed_protocols(void);
137int ir_raw_event_register(struct rc_dev *dev);
138void ir_raw_event_unregister(struct rc_dev *dev);
139int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
140void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
141void ir_raw_init(void);
142
143/*
144 * Decoder initialization code
145 *
146 * Those load logic are called during ir-core init, and automatically
147 * loads the compiled decoders for their usage with IR raw events
148 */
149
150/* from ir-nec-decoder.c */
151#ifdef CONFIG_IR_NEC_DECODER_MODULE
152#define load_nec_decode() request_module("ir-nec-decoder")
153#else
154#define load_nec_decode() 0
155#endif
156
157/* from ir-rc5-decoder.c */
158#ifdef CONFIG_IR_RC5_DECODER_MODULE
159#define load_rc5_decode() request_module("ir-rc5-decoder")
160#else
161#define load_rc5_decode() 0
162#endif
163
164/* from ir-rc6-decoder.c */
165#ifdef CONFIG_IR_RC6_DECODER_MODULE
166#define load_rc6_decode() request_module("ir-rc6-decoder")
167#else
168#define load_rc6_decode() 0
169#endif
170
171/* from ir-jvc-decoder.c */
172#ifdef CONFIG_IR_JVC_DECODER_MODULE
173#define load_jvc_decode() request_module("ir-jvc-decoder")
174#else
175#define load_jvc_decode() 0
176#endif
177
178/* from ir-sony-decoder.c */
179#ifdef CONFIG_IR_SONY_DECODER_MODULE
180#define load_sony_decode() request_module("ir-sony-decoder")
181#else
182#define load_sony_decode() 0
183#endif
184
185/* from ir-lirc-codec.c */
186#ifdef CONFIG_IR_LIRC_CODEC_MODULE
187#define load_lirc_codec() request_module("ir-lirc-codec")
188#else
189#define load_lirc_codec() 0
190#endif
191
192
193#endif /* _RC_CORE_PRIV */
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
new file mode 100644
index 000000000000..49cee61d79c6
--- /dev/null
+++ b/drivers/media/rc/rc-loopback.c
@@ -0,0 +1,260 @@
1/*
2 * Loopback driver for rc-core,
3 *
4 * Copyright (c) 2010 David Härdeman <david@hardeman.nu>
5 *
6 * This driver receives TX data and passes it back as RX data,
7 * which is useful for (scripted) debugging of rc-core without
8 * having to use actual hardware.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26#include <linux/device.h>
27#include <linux/module.h>
28#include <linux/sched.h>
29#include <media/rc-core.h>
30
31#define DRIVER_NAME "rc-loopback"
32#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x)
33#define RXMASK_REGULAR 0x1
34#define RXMASK_LEARNING 0x2
35
36static bool debug;
37
38struct loopback_dev {
39 struct rc_dev *dev;
40 u32 txmask;
41 u32 txcarrier;
42 u32 txduty;
43 bool idle;
44 bool learning;
45 bool carrierreport;
46 u32 rxcarriermin;
47 u32 rxcarriermax;
48};
49
50static struct loopback_dev loopdev;
51
52static int loop_set_tx_mask(struct rc_dev *dev, u32 mask)
53{
54 struct loopback_dev *lodev = dev->priv;
55
56 if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) {
57 dprintk("invalid tx mask: %u\n", mask);
58 return -EINVAL;
59 }
60
61 dprintk("setting tx mask: %u\n", mask);
62 lodev->txmask = mask;
63 return 0;
64}
65
66static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier)
67{
68 struct loopback_dev *lodev = dev->priv;
69
70 dprintk("setting tx carrier: %u\n", carrier);
71 lodev->txcarrier = carrier;
72 return 0;
73}
74
75static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
76{
77 struct loopback_dev *lodev = dev->priv;
78
79 if (duty_cycle < 1 || duty_cycle > 99) {
80 dprintk("invalid duty cycle: %u\n", duty_cycle);
81 return -EINVAL;
82 }
83
84 dprintk("setting duty cycle: %u\n", duty_cycle);
85 lodev->txduty = duty_cycle;
86 return 0;
87}
88
89static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
90{
91 struct loopback_dev *lodev = dev->priv;
92
93 if (min < 1 || min > max) {
94 dprintk("invalid rx carrier range %u to %u\n", min, max);
95 return -EINVAL;
96 }
97
98 dprintk("setting rx carrier range %u to %u\n", min, max);
99 lodev->rxcarriermin = min;
100 lodev->rxcarriermax = max;
101 return 0;
102}
103
104static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
105{
106 struct loopback_dev *lodev = dev->priv;
107 u32 rxmask;
108 unsigned count;
109 unsigned total_duration = 0;
110 unsigned i;
111 DEFINE_IR_RAW_EVENT(rawir);
112
113 if (n == 0 || n % sizeof(int)) {
114 dprintk("invalid tx buffer size\n");
115 return -EINVAL;
116 }
117
118 count = n / sizeof(int);
119 for (i = 0; i < count; i++)
120 total_duration += abs(txbuf[i]);
121
122 if (total_duration == 0) {
123 dprintk("invalid tx data, total duration zero\n");
124 return -EINVAL;
125 }
126
127 if (lodev->txcarrier < lodev->rxcarriermin ||
128 lodev->txcarrier > lodev->rxcarriermax) {
129 dprintk("ignoring tx, carrier out of range\n");
130 goto out;
131 }
132
133 if (lodev->learning)
134 rxmask = RXMASK_LEARNING;
135 else
136 rxmask = RXMASK_REGULAR;
137
138 if (!(rxmask & lodev->txmask)) {
139 dprintk("ignoring tx, rx mask mismatch\n");
140 goto out;
141 }
142
143 for (i = 0; i < count; i++) {
144 rawir.pulse = i % 2 ? false : true;
145 rawir.duration = abs(txbuf[i]) * 1000;
146 if (rawir.duration)
147 ir_raw_event_store_with_filter(dev, &rawir);
148 }
149 ir_raw_event_handle(dev);
150
151out:
152 /* Lirc expects this function to take as long as the total duration */
153 set_current_state(TASK_INTERRUPTIBLE);
154 schedule_timeout(usecs_to_jiffies(total_duration));
155 return n;
156}
157
158static void loop_set_idle(struct rc_dev *dev, bool enable)
159{
160 struct loopback_dev *lodev = dev->priv;
161
162 if (lodev->idle != enable) {
163 dprintk("%sing idle mode\n", enable ? "enter" : "exit");
164 lodev->idle = enable;
165 }
166}
167
168static int loop_set_learning_mode(struct rc_dev *dev, int enable)
169{
170 struct loopback_dev *lodev = dev->priv;
171
172 if (lodev->learning != enable) {
173 dprintk("%sing learning mode\n", enable ? "enter" : "exit");
174 lodev->learning = !!enable;
175 }
176
177 return 0;
178}
179
180static int loop_set_carrier_report(struct rc_dev *dev, int enable)
181{
182 struct loopback_dev *lodev = dev->priv;
183
184 if (lodev->carrierreport != enable) {
185 dprintk("%sabling carrier reports\n", enable ? "en" : "dis");
186 lodev->carrierreport = !!enable;
187 }
188
189 return 0;
190}
191
192static int __init loop_init(void)
193{
194 struct rc_dev *rc;
195 int ret;
196
197 rc = rc_allocate_device();
198 if (!rc) {
199 printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n");
200 return -ENOMEM;
201 }
202
203 rc->input_name = "rc-core loopback device";
204 rc->input_phys = "rc-core/virtual";
205 rc->input_id.bustype = BUS_VIRTUAL;
206 rc->input_id.version = 1;
207 rc->driver_name = DRIVER_NAME;
208 rc->map_name = RC_MAP_EMPTY;
209 rc->priv = &loopdev;
210 rc->driver_type = RC_DRIVER_IR_RAW;
211 rc->allowed_protos = RC_TYPE_ALL;
212 rc->timeout = 100 * 1000 * 1000; /* 100 ms */
213 rc->min_timeout = 1;
214 rc->max_timeout = UINT_MAX;
215 rc->rx_resolution = 1000;
216 rc->tx_resolution = 1000;
217 rc->s_tx_mask = loop_set_tx_mask;
218 rc->s_tx_carrier = loop_set_tx_carrier;
219 rc->s_tx_duty_cycle = loop_set_tx_duty_cycle;
220 rc->s_rx_carrier_range = loop_set_rx_carrier_range;
221 rc->tx_ir = loop_tx_ir;
222 rc->s_idle = loop_set_idle;
223 rc->s_learning_mode = loop_set_learning_mode;
224 rc->s_carrier_report = loop_set_carrier_report;
225 rc->priv = &loopdev;
226
227 loopdev.txmask = RXMASK_REGULAR;
228 loopdev.txcarrier = 36000;
229 loopdev.txduty = 50;
230 loopdev.rxcarriermin = 1;
231 loopdev.rxcarriermax = ~0;
232 loopdev.idle = true;
233 loopdev.learning = false;
234 loopdev.carrierreport = false;
235
236 ret = rc_register_device(rc);
237 if (ret < 0) {
238 printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n");
239 rc_free_device(rc);
240 return ret;
241 }
242
243 loopdev.dev = rc;
244 return 0;
245}
246
247static void __exit loop_exit(void)
248{
249 rc_unregister_device(loopdev.dev);
250}
251
252module_init(loop_init);
253module_exit(loop_exit);
254
255module_param(debug, bool, S_IRUGO | S_IWUSR);
256MODULE_PARM_DESC(debug, "Enable debug messages");
257
258MODULE_DESCRIPTION("Loopback device for rc-core debugging");
259MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
260MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
new file mode 100644
index 000000000000..72be8a02118c
--- /dev/null
+++ b/drivers/media/rc/rc-main.c
@@ -0,0 +1,1135 @@
1/* rc-main.c - Remote Controller core module
2 *
3 * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <media/rc-core.h>
16#include <linux/spinlock.h>
17#include <linux/delay.h>
18#include <linux/input.h>
19#include <linux/slab.h>
20#include <linux/device.h>
21#include "rc-core-priv.h"
22
23/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
24#define IR_TAB_MIN_SIZE 256
25#define IR_TAB_MAX_SIZE 8192
26
27/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
28#define IR_KEYPRESS_TIMEOUT 250
29
30/* Used to keep track of known keymaps */
31static LIST_HEAD(rc_map_list);
32static DEFINE_SPINLOCK(rc_map_lock);
33
34static struct rc_map_list *seek_rc_map(const char *name)
35{
36 struct rc_map_list *map = NULL;
37
38 spin_lock(&rc_map_lock);
39 list_for_each_entry(map, &rc_map_list, list) {
40 if (!strcmp(name, map->map.name)) {
41 spin_unlock(&rc_map_lock);
42 return map;
43 }
44 }
45 spin_unlock(&rc_map_lock);
46
47 return NULL;
48}
49
50struct rc_map *rc_map_get(const char *name)
51{
52
53 struct rc_map_list *map;
54
55 map = seek_rc_map(name);
56#ifdef MODULE
57 if (!map) {
58 int rc = request_module(name);
59 if (rc < 0) {
60 printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
61 return NULL;
62 }
63 msleep(20); /* Give some time for IR to register */
64
65 map = seek_rc_map(name);
66 }
67#endif
68 if (!map) {
69 printk(KERN_ERR "IR keymap %s not found\n", name);
70 return NULL;
71 }
72
73 printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
74
75 return &map->map;
76}
77EXPORT_SYMBOL_GPL(rc_map_get);
78
79int rc_map_register(struct rc_map_list *map)
80{
81 spin_lock(&rc_map_lock);
82 list_add_tail(&map->list, &rc_map_list);
83 spin_unlock(&rc_map_lock);
84 return 0;
85}
86EXPORT_SYMBOL_GPL(rc_map_register);
87
88void rc_map_unregister(struct rc_map_list *map)
89{
90 spin_lock(&rc_map_lock);
91 list_del(&map->list);
92 spin_unlock(&rc_map_lock);
93}
94EXPORT_SYMBOL_GPL(rc_map_unregister);
95
96
97static struct rc_map_table empty[] = {
98 { 0x2a, KEY_COFFEE },
99};
100
101static struct rc_map_list empty_map = {
102 .map = {
103 .scan = empty,
104 .size = ARRAY_SIZE(empty),
105 .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
106 .name = RC_MAP_EMPTY,
107 }
108};
109
110/**
111 * ir_create_table() - initializes a scancode table
112 * @rc_map: the rc_map to initialize
113 * @name: name to assign to the table
114 * @rc_type: ir type to assign to the new table
115 * @size: initial size of the table
116 * @return: zero on success or a negative error code
117 *
118 * This routine will initialize the rc_map and will allocate
119 * memory to hold at least the specified number of elements.
120 */
121static int ir_create_table(struct rc_map *rc_map,
122 const char *name, u64 rc_type, size_t size)
123{
124 rc_map->name = name;
125 rc_map->rc_type = rc_type;
126 rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
127 rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
128 rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
129 if (!rc_map->scan)
130 return -ENOMEM;
131
132 IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
133 rc_map->size, rc_map->alloc);
134 return 0;
135}
136
137/**
138 * ir_free_table() - frees memory allocated by a scancode table
139 * @rc_map: the table whose mappings need to be freed
140 *
141 * This routine will free memory alloctaed for key mappings used by given
142 * scancode table.
143 */
144static void ir_free_table(struct rc_map *rc_map)
145{
146 rc_map->size = 0;
147 kfree(rc_map->scan);
148 rc_map->scan = NULL;
149}
150
151/**
152 * ir_resize_table() - resizes a scancode table if necessary
153 * @rc_map: the rc_map to resize
154 * @gfp_flags: gfp flags to use when allocating memory
155 * @return: zero on success or a negative error code
156 *
157 * This routine will shrink the rc_map if it has lots of
158 * unused entries and grow it if it is full.
159 */
160static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
161{
162 unsigned int oldalloc = rc_map->alloc;
163 unsigned int newalloc = oldalloc;
164 struct rc_map_table *oldscan = rc_map->scan;
165 struct rc_map_table *newscan;
166
167 if (rc_map->size == rc_map->len) {
168 /* All entries in use -> grow keytable */
169 if (rc_map->alloc >= IR_TAB_MAX_SIZE)
170 return -ENOMEM;
171
172 newalloc *= 2;
173 IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
174 }
175
176 if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
177 /* Less than 1/3 of entries in use -> shrink keytable */
178 newalloc /= 2;
179 IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
180 }
181
182 if (newalloc == oldalloc)
183 return 0;
184
185 newscan = kmalloc(newalloc, gfp_flags);
186 if (!newscan) {
187 IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
188 return -ENOMEM;
189 }
190
191 memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
192 rc_map->scan = newscan;
193 rc_map->alloc = newalloc;
194 rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
195 kfree(oldscan);
196 return 0;
197}
198
199/**
200 * ir_update_mapping() - set a keycode in the scancode->keycode table
201 * @dev: the struct rc_dev device descriptor
202 * @rc_map: scancode table to be adjusted
203 * @index: index of the mapping that needs to be updated
204 * @keycode: the desired keycode
205 * @return: previous keycode assigned to the mapping
206 *
207 * This routine is used to update scancode->keycode mapping at given
208 * position.
209 */
210static unsigned int ir_update_mapping(struct rc_dev *dev,
211 struct rc_map *rc_map,
212 unsigned int index,
213 unsigned int new_keycode)
214{
215 int old_keycode = rc_map->scan[index].keycode;
216 int i;
217
218 /* Did the user wish to remove the mapping? */
219 if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
220 IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
221 index, rc_map->scan[index].scancode);
222 rc_map->len--;
223 memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
224 (rc_map->len - index) * sizeof(struct rc_map_table));
225 } else {
226 IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
227 index,
228 old_keycode == KEY_RESERVED ? "New" : "Replacing",
229 rc_map->scan[index].scancode, new_keycode);
230 rc_map->scan[index].keycode = new_keycode;
231 __set_bit(new_keycode, dev->input_dev->keybit);
232 }
233
234 if (old_keycode != KEY_RESERVED) {
235 /* A previous mapping was updated... */
236 __clear_bit(old_keycode, dev->input_dev->keybit);
237 /* ... but another scancode might use the same keycode */
238 for (i = 0; i < rc_map->len; i++) {
239 if (rc_map->scan[i].keycode == old_keycode) {
240 __set_bit(old_keycode, dev->input_dev->keybit);
241 break;
242 }
243 }
244
245 /* Possibly shrink the keytable, failure is not a problem */
246 ir_resize_table(rc_map, GFP_ATOMIC);
247 }
248
249 return old_keycode;
250}
251
252/**
253 * ir_establish_scancode() - set a keycode in the scancode->keycode table
254 * @dev: the struct rc_dev device descriptor
255 * @rc_map: scancode table to be searched
256 * @scancode: the desired scancode
257 * @resize: controls whether we allowed to resize the table to
258 * accomodate not yet present scancodes
259 * @return: index of the mapping containing scancode in question
260 * or -1U in case of failure.
261 *
262 * This routine is used to locate given scancode in rc_map.
263 * If scancode is not yet present the routine will allocate a new slot
264 * for it.
265 */
266static unsigned int ir_establish_scancode(struct rc_dev *dev,
267 struct rc_map *rc_map,
268 unsigned int scancode,
269 bool resize)
270{
271 unsigned int i;
272
273 /*
274 * Unfortunately, some hardware-based IR decoders don't provide
275 * all bits for the complete IR code. In general, they provide only
276 * the command part of the IR code. Yet, as it is possible to replace
277 * the provided IR with another one, it is needed to allow loading
278 * IR tables from other remotes. So, we support specifying a mask to
279 * indicate the valid bits of the scancodes.
280 */
281 if (dev->scanmask)
282 scancode &= dev->scanmask;
283
284 /* First check if we already have a mapping for this ir command */
285 for (i = 0; i < rc_map->len; i++) {
286 if (rc_map->scan[i].scancode == scancode)
287 return i;
288
289 /* Keytable is sorted from lowest to highest scancode */
290 if (rc_map->scan[i].scancode >= scancode)
291 break;
292 }
293
294 /* No previous mapping found, we might need to grow the table */
295 if (rc_map->size == rc_map->len) {
296 if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
297 return -1U;
298 }
299
300 /* i is the proper index to insert our new keycode */
301 if (i < rc_map->len)
302 memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
303 (rc_map->len - i) * sizeof(struct rc_map_table));
304 rc_map->scan[i].scancode = scancode;
305 rc_map->scan[i].keycode = KEY_RESERVED;
306 rc_map->len++;
307
308 return i;
309}
310
311/**
312 * ir_setkeycode() - set a keycode in the scancode->keycode table
313 * @idev: the struct input_dev device descriptor
314 * @scancode: the desired scancode
315 * @keycode: result
316 * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
317 *
318 * This routine is used to handle evdev EVIOCSKEY ioctl.
319 */
320static int ir_setkeycode(struct input_dev *idev,
321 const struct input_keymap_entry *ke,
322 unsigned int *old_keycode)
323{
324 struct rc_dev *rdev = input_get_drvdata(idev);
325 struct rc_map *rc_map = &rdev->rc_map;
326 unsigned int index;
327 unsigned int scancode;
328 int retval = 0;
329 unsigned long flags;
330
331 spin_lock_irqsave(&rc_map->lock, flags);
332
333 if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
334 index = ke->index;
335 if (index >= rc_map->len) {
336 retval = -EINVAL;
337 goto out;
338 }
339 } else {
340 retval = input_scancode_to_scalar(ke, &scancode);
341 if (retval)
342 goto out;
343
344 index = ir_establish_scancode(rdev, rc_map, scancode, true);
345 if (index >= rc_map->len) {
346 retval = -ENOMEM;
347 goto out;
348 }
349 }
350
351 *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
352
353out:
354 spin_unlock_irqrestore(&rc_map->lock, flags);
355 return retval;
356}
357
358/**
359 * ir_setkeytable() - sets several entries in the scancode->keycode table
360 * @dev: the struct rc_dev device descriptor
361 * @to: the struct rc_map to copy entries to
362 * @from: the struct rc_map to copy entries from
363 * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
364 *
365 * This routine is used to handle table initialization.
366 */
367static int ir_setkeytable(struct rc_dev *dev,
368 const struct rc_map *from)
369{
370 struct rc_map *rc_map = &dev->rc_map;
371 unsigned int i, index;
372 int rc;
373
374 rc = ir_create_table(rc_map, from->name,
375 from->rc_type, from->size);
376 if (rc)
377 return rc;
378
379 IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
380 rc_map->size, rc_map->alloc);
381
382 for (i = 0; i < from->size; i++) {
383 index = ir_establish_scancode(dev, rc_map,
384 from->scan[i].scancode, false);
385 if (index >= rc_map->len) {
386 rc = -ENOMEM;
387 break;
388 }
389
390 ir_update_mapping(dev, rc_map, index,
391 from->scan[i].keycode);
392 }
393
394 if (rc)
395 ir_free_table(rc_map);
396
397 return rc;
398}
399
400/**
401 * ir_lookup_by_scancode() - locate mapping by scancode
402 * @rc_map: the struct rc_map to search
403 * @scancode: scancode to look for in the table
404 * @return: index in the table, -1U if not found
405 *
406 * This routine performs binary search in RC keykeymap table for
407 * given scancode.
408 */
409static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
410 unsigned int scancode)
411{
412 int start = 0;
413 int end = rc_map->len - 1;
414 int mid;
415
416 while (start <= end) {
417 mid = (start + end) / 2;
418 if (rc_map->scan[mid].scancode < scancode)
419 start = mid + 1;
420 else if (rc_map->scan[mid].scancode > scancode)
421 end = mid - 1;
422 else
423 return mid;
424 }
425
426 return -1U;
427}
428
429/**
430 * ir_getkeycode() - get a keycode from the scancode->keycode table
431 * @idev: the struct input_dev device descriptor
432 * @scancode: the desired scancode
433 * @keycode: used to return the keycode, if found, or KEY_RESERVED
434 * @return: always returns zero.
435 *
436 * This routine is used to handle evdev EVIOCGKEY ioctl.
437 */
438static int ir_getkeycode(struct input_dev *idev,
439 struct input_keymap_entry *ke)
440{
441 struct rc_dev *rdev = input_get_drvdata(idev);
442 struct rc_map *rc_map = &rdev->rc_map;
443 struct rc_map_table *entry;
444 unsigned long flags;
445 unsigned int index;
446 unsigned int scancode;
447 int retval;
448
449 spin_lock_irqsave(&rc_map->lock, flags);
450
451 if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
452 index = ke->index;
453 } else {
454 retval = input_scancode_to_scalar(ke, &scancode);
455 if (retval)
456 goto out;
457
458 index = ir_lookup_by_scancode(rc_map, scancode);
459 }
460
461 if (index >= rc_map->len) {
462 if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
463 IR_dprintk(1, "unknown key for scancode 0x%04x\n",
464 scancode);
465 retval = -EINVAL;
466 goto out;
467 }
468
469 entry = &rc_map->scan[index];
470
471 ke->index = index;
472 ke->keycode = entry->keycode;
473 ke->len = sizeof(entry->scancode);
474 memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
475
476 retval = 0;
477
478out:
479 spin_unlock_irqrestore(&rc_map->lock, flags);
480 return retval;
481}
482
483/**
484 * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
485 * @dev: the struct rc_dev descriptor of the device
486 * @scancode: the scancode to look for
487 * @return: the corresponding keycode, or KEY_RESERVED
488 *
489 * This routine is used by drivers which need to convert a scancode to a
490 * keycode. Normally it should not be used since drivers should have no
491 * interest in keycodes.
492 */
493u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
494{
495 struct rc_map *rc_map = &dev->rc_map;
496 unsigned int keycode;
497 unsigned int index;
498 unsigned long flags;
499
500 spin_lock_irqsave(&rc_map->lock, flags);
501
502 index = ir_lookup_by_scancode(rc_map, scancode);
503 keycode = index < rc_map->len ?
504 rc_map->scan[index].keycode : KEY_RESERVED;
505
506 spin_unlock_irqrestore(&rc_map->lock, flags);
507
508 if (keycode != KEY_RESERVED)
509 IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
510 dev->input_name, scancode, keycode);
511
512 return keycode;
513}
514EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
515
516/**
517 * ir_do_keyup() - internal function to signal the release of a keypress
518 * @dev: the struct rc_dev descriptor of the device
519 *
520 * This function is used internally to release a keypress, it must be
521 * called with keylock held.
522 */
523static void ir_do_keyup(struct rc_dev *dev)
524{
525 if (!dev->keypressed)
526 return;
527
528 IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
529 input_report_key(dev->input_dev, dev->last_keycode, 0);
530 input_sync(dev->input_dev);
531 dev->keypressed = false;
532}
533
534/**
535 * rc_keyup() - signals the release of a keypress
536 * @dev: the struct rc_dev descriptor of the device
537 *
538 * This routine is used to signal that a key has been released on the
539 * remote control.
540 */
541void rc_keyup(struct rc_dev *dev)
542{
543 unsigned long flags;
544
545 spin_lock_irqsave(&dev->keylock, flags);
546 ir_do_keyup(dev);
547 spin_unlock_irqrestore(&dev->keylock, flags);
548}
549EXPORT_SYMBOL_GPL(rc_keyup);
550
551/**
552 * ir_timer_keyup() - generates a keyup event after a timeout
553 * @cookie: a pointer to the struct rc_dev for the device
554 *
555 * This routine will generate a keyup event some time after a keydown event
556 * is generated when no further activity has been detected.
557 */
558static void ir_timer_keyup(unsigned long cookie)
559{
560 struct rc_dev *dev = (struct rc_dev *)cookie;
561 unsigned long flags;
562
563 /*
564 * ir->keyup_jiffies is used to prevent a race condition if a
565 * hardware interrupt occurs at this point and the keyup timer
566 * event is moved further into the future as a result.
567 *
568 * The timer will then be reactivated and this function called
569 * again in the future. We need to exit gracefully in that case
570 * to allow the input subsystem to do its auto-repeat magic or
571 * a keyup event might follow immediately after the keydown.
572 */
573 spin_lock_irqsave(&dev->keylock, flags);
574 if (time_is_before_eq_jiffies(dev->keyup_jiffies))
575 ir_do_keyup(dev);
576 spin_unlock_irqrestore(&dev->keylock, flags);
577}
578
579/**
580 * rc_repeat() - signals that a key is still pressed
581 * @dev: the struct rc_dev descriptor of the device
582 *
583 * This routine is used by IR decoders when a repeat message which does
584 * not include the necessary bits to reproduce the scancode has been
585 * received.
586 */
587void rc_repeat(struct rc_dev *dev)
588{
589 unsigned long flags;
590
591 spin_lock_irqsave(&dev->keylock, flags);
592
593 input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
594
595 if (!dev->keypressed)
596 goto out;
597
598 dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
599 mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
600
601out:
602 spin_unlock_irqrestore(&dev->keylock, flags);
603}
604EXPORT_SYMBOL_GPL(rc_repeat);
605
606/**
607 * ir_do_keydown() - internal function to process a keypress
608 * @dev: the struct rc_dev descriptor of the device
609 * @scancode: the scancode of the keypress
610 * @keycode: the keycode of the keypress
611 * @toggle: the toggle value of the keypress
612 *
613 * This function is used internally to register a keypress, it must be
614 * called with keylock held.
615 */
616static void ir_do_keydown(struct rc_dev *dev, int scancode,
617 u32 keycode, u8 toggle)
618{
619 input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
620
621 /* Repeat event? */
622 if (dev->keypressed &&
623 dev->last_scancode == scancode &&
624 dev->last_toggle == toggle)
625 return;
626
627 /* Release old keypress */
628 ir_do_keyup(dev);
629
630 dev->last_scancode = scancode;
631 dev->last_toggle = toggle;
632 dev->last_keycode = keycode;
633
634 if (keycode == KEY_RESERVED)
635 return;
636
637 /* Register a keypress */
638 dev->keypressed = true;
639 IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
640 dev->input_name, keycode, scancode);
641 input_report_key(dev->input_dev, dev->last_keycode, 1);
642 input_sync(dev->input_dev);
643}
644
645/**
646 * rc_keydown() - generates input event for a key press
647 * @dev: the struct rc_dev descriptor of the device
648 * @scancode: the scancode that we're seeking
649 * @toggle: the toggle value (protocol dependent, if the protocol doesn't
650 * support toggle values, this should be set to zero)
651 *
652 * This routine is used to signal that a key has been pressed on the
653 * remote control.
654 */
655void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle)
656{
657 unsigned long flags;
658 u32 keycode = rc_g_keycode_from_table(dev, scancode);
659
660 spin_lock_irqsave(&dev->keylock, flags);
661 ir_do_keydown(dev, scancode, keycode, toggle);
662
663 if (dev->keypressed) {
664 dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
665 mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
666 }
667 spin_unlock_irqrestore(&dev->keylock, flags);
668}
669EXPORT_SYMBOL_GPL(rc_keydown);
670
671/**
672 * rc_keydown_notimeout() - generates input event for a key press without
673 * an automatic keyup event at a later time
674 * @dev: the struct rc_dev descriptor of the device
675 * @scancode: the scancode that we're seeking
676 * @toggle: the toggle value (protocol dependent, if the protocol doesn't
677 * support toggle values, this should be set to zero)
678 *
679 * This routine is used to signal that a key has been pressed on the
680 * remote control. The driver must manually call rc_keyup() at a later stage.
681 */
682void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
683{
684 unsigned long flags;
685 u32 keycode = rc_g_keycode_from_table(dev, scancode);
686
687 spin_lock_irqsave(&dev->keylock, flags);
688 ir_do_keydown(dev, scancode, keycode, toggle);
689 spin_unlock_irqrestore(&dev->keylock, flags);
690}
691EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
692
693static int ir_open(struct input_dev *idev)
694{
695 struct rc_dev *rdev = input_get_drvdata(idev);
696
697 return rdev->open(rdev);
698}
699
700static void ir_close(struct input_dev *idev)
701{
702 struct rc_dev *rdev = input_get_drvdata(idev);
703
704 rdev->close(rdev);
705}
706
707/* class for /sys/class/rc */
708static char *ir_devnode(struct device *dev, mode_t *mode)
709{
710 return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
711}
712
713static struct class ir_input_class = {
714 .name = "rc",
715 .devnode = ir_devnode,
716};
717
718static struct {
719 u64 type;
720 char *name;
721} proto_names[] = {
722 { RC_TYPE_UNKNOWN, "unknown" },
723 { RC_TYPE_RC5, "rc-5" },
724 { RC_TYPE_NEC, "nec" },
725 { RC_TYPE_RC6, "rc-6" },
726 { RC_TYPE_JVC, "jvc" },
727 { RC_TYPE_SONY, "sony" },
728 { RC_TYPE_RC5_SZ, "rc-5-sz" },
729 { RC_TYPE_LIRC, "lirc" },
730};
731
732#define PROTO_NONE "none"
733
734/**
735 * show_protocols() - shows the current IR protocol(s)
736 * @device: the device descriptor
737 * @mattr: the device attribute struct (unused)
738 * @buf: a pointer to the output buffer
739 *
740 * This routine is a callback routine for input read the IR protocol type(s).
741 * it is trigged by reading /sys/class/rc/rc?/protocols.
742 * It returns the protocol names of supported protocols.
743 * Enabled protocols are printed in brackets.
744 */
745static ssize_t show_protocols(struct device *device,
746 struct device_attribute *mattr, char *buf)
747{
748 struct rc_dev *dev = to_rc_dev(device);
749 u64 allowed, enabled;
750 char *tmp = buf;
751 int i;
752
753 /* Device is being removed */
754 if (!dev)
755 return -EINVAL;
756
757 if (dev->driver_type == RC_DRIVER_SCANCODE) {
758 enabled = dev->rc_map.rc_type;
759 allowed = dev->allowed_protos;
760 } else {
761 enabled = dev->raw->enabled_protocols;
762 allowed = ir_raw_get_allowed_protocols();
763 }
764
765 IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
766 (long long)allowed,
767 (long long)enabled);
768
769 for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
770 if (allowed & enabled & proto_names[i].type)
771 tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
772 else if (allowed & proto_names[i].type)
773 tmp += sprintf(tmp, "%s ", proto_names[i].name);
774 }
775
776 if (tmp != buf)
777 tmp--;
778 *tmp = '\n';
779 return tmp + 1 - buf;
780}
781
782/**
783 * store_protocols() - changes the current IR protocol(s)
784 * @device: the device descriptor
785 * @mattr: the device attribute struct (unused)
786 * @buf: a pointer to the input buffer
787 * @len: length of the input buffer
788 *
789 * This routine is for changing the IR protocol type.
790 * It is trigged by writing to /sys/class/rc/rc?/protocols.
791 * Writing "+proto" will add a protocol to the list of enabled protocols.
792 * Writing "-proto" will remove a protocol from the list of enabled protocols.
793 * Writing "proto" will enable only "proto".
794 * Writing "none" will disable all protocols.
795 * Returns -EINVAL if an invalid protocol combination or unknown protocol name
796 * is used, otherwise @len.
797 */
798static ssize_t store_protocols(struct device *device,
799 struct device_attribute *mattr,
800 const char *data,
801 size_t len)
802{
803 struct rc_dev *dev = to_rc_dev(device);
804 bool enable, disable;
805 const char *tmp;
806 u64 type;
807 u64 mask;
808 int rc, i, count = 0;
809 unsigned long flags;
810
811 /* Device is being removed */
812 if (!dev)
813 return -EINVAL;
814
815 if (dev->driver_type == RC_DRIVER_SCANCODE)
816 type = dev->rc_map.rc_type;
817 else if (dev->raw)
818 type = dev->raw->enabled_protocols;
819 else {
820 IR_dprintk(1, "Protocol switching not supported\n");
821 return -EINVAL;
822 }
823
824 while ((tmp = strsep((char **) &data, " \n")) != NULL) {
825 if (!*tmp)
826 break;
827
828 if (*tmp == '+') {
829 enable = true;
830 disable = false;
831 tmp++;
832 } else if (*tmp == '-') {
833 enable = false;
834 disable = true;
835 tmp++;
836 } else {
837 enable = false;
838 disable = false;
839 }
840
841 if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
842 tmp += sizeof(PROTO_NONE);
843 mask = 0;
844 count++;
845 } else {
846 for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
847 if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
848 tmp += strlen(proto_names[i].name);
849 mask = proto_names[i].type;
850 break;
851 }
852 }
853 if (i == ARRAY_SIZE(proto_names)) {
854 IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
855 return -EINVAL;
856 }
857 count++;
858 }
859
860 if (enable)
861 type |= mask;
862 else if (disable)
863 type &= ~mask;
864 else
865 type = mask;
866 }
867
868 if (!count) {
869 IR_dprintk(1, "Protocol not specified\n");
870 return -EINVAL;
871 }
872
873 if (dev->change_protocol) {
874 rc = dev->change_protocol(dev, type);
875 if (rc < 0) {
876 IR_dprintk(1, "Error setting protocols to 0x%llx\n",
877 (long long)type);
878 return -EINVAL;
879 }
880 }
881
882 if (dev->driver_type == RC_DRIVER_SCANCODE) {
883 spin_lock_irqsave(&dev->rc_map.lock, flags);
884 dev->rc_map.rc_type = type;
885 spin_unlock_irqrestore(&dev->rc_map.lock, flags);
886 } else {
887 dev->raw->enabled_protocols = type;
888 }
889
890 IR_dprintk(1, "Current protocol(s): 0x%llx\n",
891 (long long)type);
892
893 return len;
894}
895
896static void rc_dev_release(struct device *device)
897{
898 struct rc_dev *dev = to_rc_dev(device);
899
900 kfree(dev);
901 module_put(THIS_MODULE);
902}
903
904#define ADD_HOTPLUG_VAR(fmt, val...) \
905 do { \
906 int err = add_uevent_var(env, fmt, val); \
907 if (err) \
908 return err; \
909 } while (0)
910
911static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
912{
913 struct rc_dev *dev = to_rc_dev(device);
914
915 if (dev->rc_map.name)
916 ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
917 if (dev->driver_name)
918 ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
919
920 return 0;
921}
922
923/*
924 * Static device attribute struct with the sysfs attributes for IR's
925 */
926static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
927 show_protocols, store_protocols);
928
929static struct attribute *rc_dev_attrs[] = {
930 &dev_attr_protocols.attr,
931 NULL,
932};
933
934static struct attribute_group rc_dev_attr_grp = {
935 .attrs = rc_dev_attrs,
936};
937
938static const struct attribute_group *rc_dev_attr_groups[] = {
939 &rc_dev_attr_grp,
940 NULL
941};
942
943static struct device_type rc_dev_type = {
944 .groups = rc_dev_attr_groups,
945 .release = rc_dev_release,
946 .uevent = rc_dev_uevent,
947};
948
949struct rc_dev *rc_allocate_device(void)
950{
951 struct rc_dev *dev;
952
953 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
954 if (!dev)
955 return NULL;
956
957 dev->input_dev = input_allocate_device();
958 if (!dev->input_dev) {
959 kfree(dev);
960 return NULL;
961 }
962
963 dev->input_dev->getkeycode_new = ir_getkeycode;
964 dev->input_dev->setkeycode_new = ir_setkeycode;
965 input_set_drvdata(dev->input_dev, dev);
966
967 spin_lock_init(&dev->rc_map.lock);
968 spin_lock_init(&dev->keylock);
969 setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
970
971 dev->dev.type = &rc_dev_type;
972 dev->dev.class = &ir_input_class;
973 device_initialize(&dev->dev);
974
975 __module_get(THIS_MODULE);
976 return dev;
977}
978EXPORT_SYMBOL_GPL(rc_allocate_device);
979
980void rc_free_device(struct rc_dev *dev)
981{
982 if (dev) {
983 input_free_device(dev->input_dev);
984 put_device(&dev->dev);
985 }
986}
987EXPORT_SYMBOL_GPL(rc_free_device);
988
989int rc_register_device(struct rc_dev *dev)
990{
991 static atomic_t devno = ATOMIC_INIT(0);
992 struct rc_map *rc_map;
993 const char *path;
994 int rc;
995
996 if (!dev || !dev->map_name)
997 return -EINVAL;
998
999 rc_map = rc_map_get(dev->map_name);
1000 if (!rc_map)
1001 rc_map = rc_map_get(RC_MAP_EMPTY);
1002 if (!rc_map || !rc_map->scan || rc_map->size == 0)
1003 return -EINVAL;
1004
1005 set_bit(EV_KEY, dev->input_dev->evbit);
1006 set_bit(EV_REP, dev->input_dev->evbit);
1007 set_bit(EV_MSC, dev->input_dev->evbit);
1008 set_bit(MSC_SCAN, dev->input_dev->mscbit);
1009 if (dev->open)
1010 dev->input_dev->open = ir_open;
1011 if (dev->close)
1012 dev->input_dev->close = ir_close;
1013
1014 dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
1015 dev_set_name(&dev->dev, "rc%ld", dev->devno);
1016 dev_set_drvdata(&dev->dev, dev);
1017 rc = device_add(&dev->dev);
1018 if (rc)
1019 return rc;
1020
1021 rc = ir_setkeytable(dev, rc_map);
1022 if (rc)
1023 goto out_dev;
1024
1025 dev->input_dev->dev.parent = &dev->dev;
1026 memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
1027 dev->input_dev->phys = dev->input_phys;
1028 dev->input_dev->name = dev->input_name;
1029 rc = input_register_device(dev->input_dev);
1030 if (rc)
1031 goto out_table;
1032
1033 /*
1034 * Default delay of 250ms is too short for some protocols, expecially
1035 * since the timeout is currently set to 250ms. Increase it to 500ms,
1036 * to avoid wrong repetition of the keycodes. Note that this must be
1037 * set after the call to input_register_device().
1038 */
1039 dev->input_dev->rep[REP_DELAY] = 500;
1040
1041 path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
1042 printk(KERN_INFO "%s: %s as %s\n",
1043 dev_name(&dev->dev),
1044 dev->input_name ? dev->input_name : "Unspecified device",
1045 path ? path : "N/A");
1046 kfree(path);
1047
1048 if (dev->driver_type == RC_DRIVER_IR_RAW) {
1049 rc = ir_raw_event_register(dev);
1050 if (rc < 0)
1051 goto out_input;
1052 }
1053
1054 if (dev->change_protocol) {
1055 rc = dev->change_protocol(dev, rc_map->rc_type);
1056 if (rc < 0)
1057 goto out_raw;
1058 }
1059
1060 IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
1061 dev->devno,
1062 dev->driver_name ? dev->driver_name : "unknown",
1063 rc_map->name ? rc_map->name : "unknown",
1064 dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
1065
1066 return 0;
1067
1068out_raw:
1069 if (dev->driver_type == RC_DRIVER_IR_RAW)
1070 ir_raw_event_unregister(dev);
1071out_input:
1072 input_unregister_device(dev->input_dev);
1073 dev->input_dev = NULL;
1074out_table:
1075 ir_free_table(&dev->rc_map);
1076out_dev:
1077 device_del(&dev->dev);
1078 return rc;
1079}
1080EXPORT_SYMBOL_GPL(rc_register_device);
1081
1082void rc_unregister_device(struct rc_dev *dev)
1083{
1084 if (!dev)
1085 return;
1086
1087 del_timer_sync(&dev->timer_keyup);
1088
1089 if (dev->driver_type == RC_DRIVER_IR_RAW)
1090 ir_raw_event_unregister(dev);
1091
1092 input_unregister_device(dev->input_dev);
1093 dev->input_dev = NULL;
1094
1095 ir_free_table(&dev->rc_map);
1096 IR_dprintk(1, "Freed keycode table\n");
1097
1098 device_unregister(&dev->dev);
1099}
1100EXPORT_SYMBOL_GPL(rc_unregister_device);
1101
1102/*
1103 * Init/exit code for the module. Basically, creates/removes /sys/class/rc
1104 */
1105
1106static int __init rc_core_init(void)
1107{
1108 int rc = class_register(&ir_input_class);
1109 if (rc) {
1110 printk(KERN_ERR "rc_core: unable to register rc class\n");
1111 return rc;
1112 }
1113
1114 /* Initialize/load the decoders/keymap code that will be used */
1115 ir_raw_init();
1116 rc_map_register(&empty_map);
1117
1118 return 0;
1119}
1120
1121static void __exit rc_core_exit(void)
1122{
1123 class_unregister(&ir_input_class);
1124 rc_map_unregister(&empty_map);
1125}
1126
1127module_init(rc_core_init);
1128module_exit(rc_core_exit);
1129
1130int rc_core_debug; /* ir_debug level (0,1,2) */
1131EXPORT_SYMBOL_GPL(rc_core_debug);
1132module_param_named(debug, rc_core_debug, int, 0644);
1133
1134MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
1135MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
new file mode 100644
index 000000000000..6e2911c2abfb
--- /dev/null
+++ b/drivers/media/rc/streamzap.c
@@ -0,0 +1,557 @@
1/*
2 * Streamzap Remote Control driver
3 *
4 * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de>
5 * Copyright (c) 2010 Jarod Wilson <jarod@wilsonet.com>
6 *
7 * This driver was based on the work of Greg Wickham and Adrian
8 * Dewhurst. It was substantially rewritten to support correct signal
9 * gaps and now maintains a delay buffer, which is used to present
10 * consistent timing behaviour to user space applications. Without the
11 * delay buffer an ugly hack would be required in lircd, which can
12 * cause sluggish signal decoding in certain situations.
13 *
14 * Ported to in-kernel ir-core interface by Jarod Wilson
15 *
16 * This driver is based on the USB skeleton driver packaged with the
17 * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 */
33
34#include <linux/device.h>
35#include <linux/module.h>
36#include <linux/slab.h>
37#include <linux/usb.h>
38#include <linux/usb/input.h>
39#include <media/rc-core.h>
40
41#define DRIVER_VERSION "1.61"
42#define DRIVER_NAME "streamzap"
43#define DRIVER_DESC "Streamzap Remote Control driver"
44
45#ifdef CONFIG_USB_DEBUG
46static int debug = 1;
47#else
48static int debug;
49#endif
50
51#define USB_STREAMZAP_VENDOR_ID 0x0e9c
52#define USB_STREAMZAP_PRODUCT_ID 0x0000
53
54/* table of devices that work with this driver */
55static struct usb_device_id streamzap_table[] = {
56 /* Streamzap Remote Control */
57 { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) },
58 /* Terminating entry */
59 { }
60};
61
62MODULE_DEVICE_TABLE(usb, streamzap_table);
63
64#define SZ_PULSE_MASK 0xf0
65#define SZ_SPACE_MASK 0x0f
66#define SZ_TIMEOUT 0xff
67#define SZ_RESOLUTION 256
68
69/* number of samples buffered */
70#define SZ_BUF_LEN 128
71
72/* from ir-rc5-sz-decoder.c */
73#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
74#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder")
75#else
76#define load_rc5_sz_decode() {}
77#endif
78
79enum StreamzapDecoderState {
80 PulseSpace,
81 FullPulse,
82 FullSpace,
83 IgnorePulse
84};
85
86/* structure to hold our device specific stuff */
87struct streamzap_ir {
88 /* ir-core */
89 struct rc_dev *rdev;
90
91 /* core device info */
92 struct device *dev;
93
94 /* usb */
95 struct usb_device *usbdev;
96 struct usb_interface *interface;
97 struct usb_endpoint_descriptor *endpoint;
98 struct urb *urb_in;
99
100 /* buffer & dma */
101 unsigned char *buf_in;
102 dma_addr_t dma_in;
103 unsigned int buf_in_len;
104
105 /* track what state we're in */
106 enum StreamzapDecoderState decoder_state;
107 /* tracks whether we are currently receiving some signal */
108 bool idle;
109 /* sum of signal lengths received since signal start */
110 unsigned long sum;
111 /* start time of signal; necessary for gap tracking */
112 struct timeval signal_last;
113 struct timeval signal_start;
114 bool timeout_enabled;
115
116 char name[128];
117 char phys[64];
118};
119
120
121/* local function prototypes */
122static int streamzap_probe(struct usb_interface *interface,
123 const struct usb_device_id *id);
124static void streamzap_disconnect(struct usb_interface *interface);
125static void streamzap_callback(struct urb *urb);
126static int streamzap_suspend(struct usb_interface *intf, pm_message_t message);
127static int streamzap_resume(struct usb_interface *intf);
128
129/* usb specific object needed to register this driver with the usb subsystem */
130static struct usb_driver streamzap_driver = {
131 .name = DRIVER_NAME,
132 .probe = streamzap_probe,
133 .disconnect = streamzap_disconnect,
134 .suspend = streamzap_suspend,
135 .resume = streamzap_resume,
136 .id_table = streamzap_table,
137};
138
139static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
140{
141 dev_dbg(sz->dev, "Storing %s with duration %u us\n",
142 (rawir.pulse ? "pulse" : "space"), rawir.duration);
143 ir_raw_event_store_with_filter(sz->rdev, &rawir);
144}
145
146static void sz_push_full_pulse(struct streamzap_ir *sz,
147 unsigned char value)
148{
149 DEFINE_IR_RAW_EVENT(rawir);
150
151 if (sz->idle) {
152 long deltv;
153
154 sz->signal_last = sz->signal_start;
155 do_gettimeofday(&sz->signal_start);
156
157 deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
158 rawir.pulse = false;
159 if (deltv > 15) {
160 /* really long time */
161 rawir.duration = IR_MAX_DURATION;
162 } else {
163 rawir.duration = (int)(deltv * 1000000 +
164 sz->signal_start.tv_usec -
165 sz->signal_last.tv_usec);
166 rawir.duration -= sz->sum;
167 rawir.duration *= 1000;
168 rawir.duration &= IR_MAX_DURATION;
169 }
170 sz_push(sz, rawir);
171
172 sz->idle = false;
173 sz->sum = 0;
174 }
175
176 rawir.pulse = true;
177 rawir.duration = ((int) value) * SZ_RESOLUTION;
178 rawir.duration += SZ_RESOLUTION / 2;
179 sz->sum += rawir.duration;
180 rawir.duration *= 1000;
181 rawir.duration &= IR_MAX_DURATION;
182 sz_push(sz, rawir);
183}
184
185static void sz_push_half_pulse(struct streamzap_ir *sz,
186 unsigned char value)
187{
188 sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4);
189}
190
191static void sz_push_full_space(struct streamzap_ir *sz,
192 unsigned char value)
193{
194 DEFINE_IR_RAW_EVENT(rawir);
195
196 rawir.pulse = false;
197 rawir.duration = ((int) value) * SZ_RESOLUTION;
198 rawir.duration += SZ_RESOLUTION / 2;
199 sz->sum += rawir.duration;
200 rawir.duration *= 1000;
201 sz_push(sz, rawir);
202}
203
204static void sz_push_half_space(struct streamzap_ir *sz,
205 unsigned long value)
206{
207 sz_push_full_space(sz, value & SZ_SPACE_MASK);
208}
209
210/**
211 * streamzap_callback - usb IRQ handler callback
212 *
213 * This procedure is invoked on reception of data from
214 * the usb remote.
215 */
216static void streamzap_callback(struct urb *urb)
217{
218 struct streamzap_ir *sz;
219 unsigned int i;
220 int len;
221
222 if (!urb)
223 return;
224
225 sz = urb->context;
226 len = urb->actual_length;
227
228 switch (urb->status) {
229 case -ECONNRESET:
230 case -ENOENT:
231 case -ESHUTDOWN:
232 /*
233 * this urb is terminated, clean up.
234 * sz might already be invalid at this point
235 */
236 dev_err(sz->dev, "urb terminated, status: %d\n", urb->status);
237 return;
238 default:
239 break;
240 }
241
242 dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
243 for (i = 0; i < len; i++) {
244 dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n",
245 i, (unsigned char)sz->buf_in[i]);
246 switch (sz->decoder_state) {
247 case PulseSpace:
248 if ((sz->buf_in[i] & SZ_PULSE_MASK) ==
249 SZ_PULSE_MASK) {
250 sz->decoder_state = FullPulse;
251 continue;
252 } else if ((sz->buf_in[i] & SZ_SPACE_MASK)
253 == SZ_SPACE_MASK) {
254 sz_push_half_pulse(sz, sz->buf_in[i]);
255 sz->decoder_state = FullSpace;
256 continue;
257 } else {
258 sz_push_half_pulse(sz, sz->buf_in[i]);
259 sz_push_half_space(sz, sz->buf_in[i]);
260 }
261 break;
262 case FullPulse:
263 sz_push_full_pulse(sz, sz->buf_in[i]);
264 sz->decoder_state = IgnorePulse;
265 break;
266 case FullSpace:
267 if (sz->buf_in[i] == SZ_TIMEOUT) {
268 DEFINE_IR_RAW_EVENT(rawir);
269
270 rawir.pulse = false;
271 rawir.duration = sz->rdev->timeout;
272 sz->idle = true;
273 if (sz->timeout_enabled)
274 sz_push(sz, rawir);
275 ir_raw_event_handle(sz->rdev);
276 } else {
277 sz_push_full_space(sz, sz->buf_in[i]);
278 }
279 sz->decoder_state = PulseSpace;
280 break;
281 case IgnorePulse:
282 if ((sz->buf_in[i] & SZ_SPACE_MASK) ==
283 SZ_SPACE_MASK) {
284 sz->decoder_state = FullSpace;
285 continue;
286 }
287 sz_push_half_space(sz, sz->buf_in[i]);
288 sz->decoder_state = PulseSpace;
289 break;
290 }
291 }
292
293 usb_submit_urb(urb, GFP_ATOMIC);
294
295 return;
296}
297
298static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
299{
300 struct rc_dev *rdev;
301 struct device *dev = sz->dev;
302 int ret;
303
304 rdev = rc_allocate_device();
305 if (!rdev) {
306 dev_err(dev, "remote dev allocation failed\n");
307 goto out;
308 }
309
310 snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared "
311 "Receiver (%04x:%04x)",
312 le16_to_cpu(sz->usbdev->descriptor.idVendor),
313 le16_to_cpu(sz->usbdev->descriptor.idProduct));
314 usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys));
315 strlcat(sz->phys, "/input0", sizeof(sz->phys));
316
317 rdev->input_name = sz->name;
318 rdev->input_phys = sz->phys;
319 usb_to_input_id(sz->usbdev, &rdev->input_id);
320 rdev->dev.parent = dev;
321 rdev->priv = sz;
322 rdev->driver_type = RC_DRIVER_IR_RAW;
323 rdev->allowed_protos = RC_TYPE_ALL;
324 rdev->driver_name = DRIVER_NAME;
325 rdev->map_name = RC_MAP_STREAMZAP;
326
327 ret = rc_register_device(rdev);
328 if (ret < 0) {
329 dev_err(dev, "remote input device register failed\n");
330 goto out;
331 }
332
333 return rdev;
334
335out:
336 rc_free_device(rdev);
337 return NULL;
338}
339
340/**
341 * streamzap_probe
342 *
343 * Called by usb-core to associated with a candidate device
344 * On any failure the return value is the ERROR
345 * On success return 0
346 */
347static int __devinit streamzap_probe(struct usb_interface *intf,
348 const struct usb_device_id *id)
349{
350 struct usb_device *usbdev = interface_to_usbdev(intf);
351 struct usb_host_interface *iface_host;
352 struct streamzap_ir *sz = NULL;
353 char buf[63], name[128] = "";
354 int retval = -ENOMEM;
355 int pipe, maxp;
356
357 /* Allocate space for device driver specific data */
358 sz = kzalloc(sizeof(struct streamzap_ir), GFP_KERNEL);
359 if (!sz)
360 return -ENOMEM;
361
362 sz->usbdev = usbdev;
363 sz->interface = intf;
364
365 /* Check to ensure endpoint information matches requirements */
366 iface_host = intf->cur_altsetting;
367
368 if (iface_host->desc.bNumEndpoints != 1) {
369 dev_err(&intf->dev, "%s: Unexpected desc.bNumEndpoints (%d)\n",
370 __func__, iface_host->desc.bNumEndpoints);
371 retval = -ENODEV;
372 goto free_sz;
373 }
374
375 sz->endpoint = &(iface_host->endpoint[0].desc);
376 if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
377 != USB_DIR_IN) {
378 dev_err(&intf->dev, "%s: endpoint doesn't match input device "
379 "02%02x\n", __func__, sz->endpoint->bEndpointAddress);
380 retval = -ENODEV;
381 goto free_sz;
382 }
383
384 if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
385 != USB_ENDPOINT_XFER_INT) {
386 dev_err(&intf->dev, "%s: endpoint attributes don't match xfer "
387 "02%02x\n", __func__, sz->endpoint->bmAttributes);
388 retval = -ENODEV;
389 goto free_sz;
390 }
391
392 pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress);
393 maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe));
394
395 if (maxp == 0) {
396 dev_err(&intf->dev, "%s: endpoint Max Packet Size is 0!?!\n",
397 __func__);
398 retval = -ENODEV;
399 goto free_sz;
400 }
401
402 /* Allocate the USB buffer and IRQ URB */
403 sz->buf_in = usb_alloc_coherent(usbdev, maxp, GFP_ATOMIC, &sz->dma_in);
404 if (!sz->buf_in)
405 goto free_sz;
406
407 sz->urb_in = usb_alloc_urb(0, GFP_KERNEL);
408 if (!sz->urb_in)
409 goto free_buf_in;
410
411 sz->dev = &intf->dev;
412 sz->buf_in_len = maxp;
413
414 if (usbdev->descriptor.iManufacturer
415 && usb_string(usbdev, usbdev->descriptor.iManufacturer,
416 buf, sizeof(buf)) > 0)
417 strlcpy(name, buf, sizeof(name));
418
419 if (usbdev->descriptor.iProduct
420 && usb_string(usbdev, usbdev->descriptor.iProduct,
421 buf, sizeof(buf)) > 0)
422 snprintf(name + strlen(name), sizeof(name) - strlen(name),
423 " %s", buf);
424
425 sz->rdev = streamzap_init_rc_dev(sz);
426 if (!sz->rdev)
427 goto rc_dev_fail;
428
429 sz->idle = true;
430 sz->decoder_state = PulseSpace;
431 /* FIXME: don't yet have a way to set this */
432 sz->timeout_enabled = true;
433 sz->rdev->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
434 IR_MAX_DURATION) | 0x03000000);
435 #if 0
436 /* not yet supported, depends on patches from maxim */
437 /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
438 sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
439 sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
440 #endif
441
442 do_gettimeofday(&sz->signal_start);
443
444 /* Complete final initialisations */
445 usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in,
446 maxp, (usb_complete_t)streamzap_callback,
447 sz, sz->endpoint->bInterval);
448 sz->urb_in->transfer_dma = sz->dma_in;
449 sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
450
451 usb_set_intfdata(intf, sz);
452
453 if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
454 dev_err(sz->dev, "urb submit failed\n");
455
456 dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
457 usbdev->bus->busnum, usbdev->devnum);
458
459 /* Load the streamzap not-quite-rc5 decoder too */
460 load_rc5_sz_decode();
461
462 return 0;
463
464rc_dev_fail:
465 usb_free_urb(sz->urb_in);
466free_buf_in:
467 usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
468free_sz:
469 kfree(sz);
470
471 return retval;
472}
473
474/**
475 * streamzap_disconnect
476 *
477 * Called by the usb core when the device is removed from the system.
478 *
479 * This routine guarantees that the driver will not submit any more urbs
480 * by clearing dev->usbdev. It is also supposed to terminate any currently
481 * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(),
482 * does not provide any way to do this.
483 */
484static void streamzap_disconnect(struct usb_interface *interface)
485{
486 struct streamzap_ir *sz = usb_get_intfdata(interface);
487 struct usb_device *usbdev = interface_to_usbdev(interface);
488
489 usb_set_intfdata(interface, NULL);
490
491 if (!sz)
492 return;
493
494 sz->usbdev = NULL;
495 rc_unregister_device(sz->rdev);
496 usb_kill_urb(sz->urb_in);
497 usb_free_urb(sz->urb_in);
498 usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
499
500 kfree(sz);
501}
502
503static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
504{
505 struct streamzap_ir *sz = usb_get_intfdata(intf);
506
507 usb_kill_urb(sz->urb_in);
508
509 return 0;
510}
511
512static int streamzap_resume(struct usb_interface *intf)
513{
514 struct streamzap_ir *sz = usb_get_intfdata(intf);
515
516 if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
517 dev_err(sz->dev, "Error sumbiting urb\n");
518 return -EIO;
519 }
520
521 return 0;
522}
523
524/**
525 * streamzap_init
526 */
527static int __init streamzap_init(void)
528{
529 int ret;
530
531 /* register this driver with the USB subsystem */
532 ret = usb_register(&streamzap_driver);
533 if (ret < 0)
534 printk(KERN_ERR DRIVER_NAME ": usb register failed, "
535 "result = %d\n", ret);
536
537 return ret;
538}
539
540/**
541 * streamzap_exit
542 */
543static void __exit streamzap_exit(void)
544{
545 usb_deregister(&streamzap_driver);
546}
547
548
549module_init(streamzap_init);
550module_exit(streamzap_exit);
551
552MODULE_AUTHOR("Jarod Wilson <jarod@wilsonet.com>");
553MODULE_DESCRIPTION(DRIVER_DESC);
554MODULE_LICENSE("GPL");
555
556module_param(debug, bool, S_IRUGO | S_IWUSR);
557MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
new file mode 100644
index 000000000000..186de5522001
--- /dev/null
+++ b/drivers/media/rc/winbond-cir.c
@@ -0,0 +1,932 @@
1/*
2 * winbond-cir.c - Driver for the Consumer IR functionality of Winbond
3 * SuperI/O chips.
4 *
5 * Currently supports the Winbond WPCD376i chip (PNP id WEC1022), but
6 * could probably support others (Winbond WEC102X, NatSemi, etc)
7 * with minor modifications.
8 *
9 * Original Author: David Härdeman <david@hardeman.nu>
10 * Copyright (C) 2009 - 2010 David Härdeman <david@hardeman.nu>
11 *
12 * Dedicated to my daughter Matilda, without whose loving attention this
13 * driver would have been finished in half the time and with a fraction
14 * of the bugs.
15 *
16 * Written using:
17 * o Winbond WPCD376I datasheet helpfully provided by Jesse Barnes at Intel
18 * o NatSemi PC87338/PC97338 datasheet (for the serial port stuff)
19 * o DSDT dumps
20 *
21 * Supported features:
22 * o Wake-On-CIR functionality
23 *
24 * To do:
25 * o Learning
26 * o IR Transmit
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation; either version 2 of the License, or
31 * (at your option) any later version.
32 *
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
37 *
38 * You should have received a copy of the GNU General Public License
39 * along with this program; if not, write to the Free Software
40 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
41 */
42
43#include <linux/module.h>
44#include <linux/pnp.h>
45#include <linux/interrupt.h>
46#include <linux/timer.h>
47#include <linux/leds.h>
48#include <linux/spinlock.h>
49#include <linux/pci_ids.h>
50#include <linux/io.h>
51#include <linux/bitrev.h>
52#include <linux/slab.h>
53#include <media/rc-core.h>
54
55#define DRVNAME "winbond-cir"
56
57/* CEIR Wake-Up Registers, relative to data->wbase */
58#define WBCIR_REG_WCEIR_CTL 0x03 /* CEIR Receiver Control */
59#define WBCIR_REG_WCEIR_STS 0x04 /* CEIR Receiver Status */
60#define WBCIR_REG_WCEIR_EV_EN 0x05 /* CEIR Receiver Event Enable */
61#define WBCIR_REG_WCEIR_CNTL 0x06 /* CEIR Receiver Counter Low */
62#define WBCIR_REG_WCEIR_CNTH 0x07 /* CEIR Receiver Counter High */
63#define WBCIR_REG_WCEIR_INDEX 0x08 /* CEIR Receiver Index */
64#define WBCIR_REG_WCEIR_DATA 0x09 /* CEIR Receiver Data */
65#define WBCIR_REG_WCEIR_CSL 0x0A /* CEIR Re. Compare Strlen */
66#define WBCIR_REG_WCEIR_CFG1 0x0B /* CEIR Re. Configuration 1 */
67#define WBCIR_REG_WCEIR_CFG2 0x0C /* CEIR Re. Configuration 2 */
68
69/* CEIR Enhanced Functionality Registers, relative to data->ebase */
70#define WBCIR_REG_ECEIR_CTS 0x00 /* Enhanced IR Control Status */
71#define WBCIR_REG_ECEIR_CCTL 0x01 /* Infrared Counter Control */
72#define WBCIR_REG_ECEIR_CNT_LO 0x02 /* Infrared Counter LSB */
73#define WBCIR_REG_ECEIR_CNT_HI 0x03 /* Infrared Counter MSB */
74#define WBCIR_REG_ECEIR_IREM 0x04 /* Infrared Emitter Status */
75
76/* SP3 Banked Registers, relative to data->sbase */
77#define WBCIR_REG_SP3_BSR 0x03 /* Bank Select, all banks */
78 /* Bank 0 */
79#define WBCIR_REG_SP3_RXDATA 0x00 /* FIFO RX data (r) */
80#define WBCIR_REG_SP3_TXDATA 0x00 /* FIFO TX data (w) */
81#define WBCIR_REG_SP3_IER 0x01 /* Interrupt Enable */
82#define WBCIR_REG_SP3_EIR 0x02 /* Event Identification (r) */
83#define WBCIR_REG_SP3_FCR 0x02 /* FIFO Control (w) */
84#define WBCIR_REG_SP3_MCR 0x04 /* Mode Control */
85#define WBCIR_REG_SP3_LSR 0x05 /* Link Status */
86#define WBCIR_REG_SP3_MSR 0x06 /* Modem Status */
87#define WBCIR_REG_SP3_ASCR 0x07 /* Aux Status and Control */
88 /* Bank 2 */
89#define WBCIR_REG_SP3_BGDL 0x00 /* Baud Divisor LSB */
90#define WBCIR_REG_SP3_BGDH 0x01 /* Baud Divisor MSB */
91#define WBCIR_REG_SP3_EXCR1 0x02 /* Extended Control 1 */
92#define WBCIR_REG_SP3_EXCR2 0x04 /* Extended Control 2 */
93#define WBCIR_REG_SP3_TXFLV 0x06 /* TX FIFO Level */
94#define WBCIR_REG_SP3_RXFLV 0x07 /* RX FIFO Level */
95 /* Bank 3 */
96#define WBCIR_REG_SP3_MRID 0x00 /* Module Identification */
97#define WBCIR_REG_SP3_SH_LCR 0x01 /* LCR Shadow */
98#define WBCIR_REG_SP3_SH_FCR 0x02 /* FCR Shadow */
99 /* Bank 4 */
100#define WBCIR_REG_SP3_IRCR1 0x02 /* Infrared Control 1 */
101 /* Bank 5 */
102#define WBCIR_REG_SP3_IRCR2 0x04 /* Infrared Control 2 */
103 /* Bank 6 */
104#define WBCIR_REG_SP3_IRCR3 0x00 /* Infrared Control 3 */
105#define WBCIR_REG_SP3_SIR_PW 0x02 /* SIR Pulse Width */
106 /* Bank 7 */
107#define WBCIR_REG_SP3_IRRXDC 0x00 /* IR RX Demod Control */
108#define WBCIR_REG_SP3_IRTXMC 0x01 /* IR TX Mod Control */
109#define WBCIR_REG_SP3_RCCFG 0x02 /* CEIR Config */
110#define WBCIR_REG_SP3_IRCFG1 0x04 /* Infrared Config 1 */
111#define WBCIR_REG_SP3_IRCFG4 0x07 /* Infrared Config 4 */
112
113/*
114 * Magic values follow
115 */
116
117/* No interrupts for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
118#define WBCIR_IRQ_NONE 0x00
119/* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
120#define WBCIR_IRQ_RX 0x01
121/* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
122#define WBCIR_IRQ_ERR 0x04
123/* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */
124#define WBCIR_LED_ENABLE 0x80
125/* RX data available bit for WBCIR_REG_SP3_LSR */
126#define WBCIR_RX_AVAIL 0x01
127/* RX disable bit for WBCIR_REG_SP3_ASCR */
128#define WBCIR_RX_DISABLE 0x20
129/* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */
130#define WBCIR_EXT_ENABLE 0x01
131/* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */
132#define WBCIR_REGSEL_COMPARE 0x10
133/* Select mask register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */
134#define WBCIR_REGSEL_MASK 0x20
135/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */
136#define WBCIR_REG_ADDR0 0x00
137
138/* Valid banks for the SP3 UART */
139enum wbcir_bank {
140 WBCIR_BANK_0 = 0x00,
141 WBCIR_BANK_1 = 0x80,
142 WBCIR_BANK_2 = 0xE0,
143 WBCIR_BANK_3 = 0xE4,
144 WBCIR_BANK_4 = 0xE8,
145 WBCIR_BANK_5 = 0xEC,
146 WBCIR_BANK_6 = 0xF0,
147 WBCIR_BANK_7 = 0xF4,
148};
149
150/* Supported power-on IR Protocols */
151enum wbcir_protocol {
152 IR_PROTOCOL_RC5 = 0x0,
153 IR_PROTOCOL_NEC = 0x1,
154 IR_PROTOCOL_RC6 = 0x2,
155};
156
157/* Misc */
158#define WBCIR_NAME "Winbond CIR"
159#define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */
160#define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */
161#define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */
162#define WAKEUP_IOMEM_LEN 0x10 /* Wake-Up I/O Reg Len */
163#define EHFUNC_IOMEM_LEN 0x10 /* Enhanced Func I/O Reg Len */
164#define SP_IOMEM_LEN 0x08 /* Serial Port 3 (IR) Reg Len */
165
166/* Per-device data */
167struct wbcir_data {
168 spinlock_t spinlock;
169
170 unsigned long wbase; /* Wake-Up Baseaddr */
171 unsigned long ebase; /* Enhanced Func. Baseaddr */
172 unsigned long sbase; /* Serial Port Baseaddr */
173 unsigned int irq; /* Serial Port IRQ */
174
175 struct rc_dev *dev;
176
177 struct led_trigger *rxtrigger;
178 struct led_trigger *txtrigger;
179 struct led_classdev led;
180
181 /* RX irdata state */
182 bool irdata_active;
183 bool irdata_error;
184 struct ir_raw_event ev;
185};
186
187static enum wbcir_protocol protocol = IR_PROTOCOL_RC6;
188module_param(protocol, uint, 0444);
189MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command "
190 "(0 = RC5, 1 = NEC, 2 = RC6A, default)");
191
192static int invert; /* default = 0 */
193module_param(invert, bool, 0444);
194MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
195
196static unsigned int wake_sc = 0x800F040C;
197module_param(wake_sc, uint, 0644);
198MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command");
199
200static unsigned int wake_rc6mode = 6;
201module_param(wake_rc6mode, uint, 0644);
202MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command "
203 "(0 = 0, 6 = 6A, default)");
204
205
206
207/*****************************************************************************
208 *
209 * UTILITY FUNCTIONS
210 *
211 *****************************************************************************/
212
213/* Caller needs to hold wbcir_lock */
214static void
215wbcir_set_bits(unsigned long addr, u8 bits, u8 mask)
216{
217 u8 val;
218
219 val = inb(addr);
220 val = ((val & ~mask) | (bits & mask));
221 outb(val, addr);
222}
223
224/* Selects the register bank for the serial port */
225static inline void
226wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank)
227{
228 outb(bank, data->sbase + WBCIR_REG_SP3_BSR);
229}
230
231static enum led_brightness
232wbcir_led_brightness_get(struct led_classdev *led_cdev)
233{
234 struct wbcir_data *data = container_of(led_cdev,
235 struct wbcir_data,
236 led);
237
238 if (inb(data->ebase + WBCIR_REG_ECEIR_CTS) & WBCIR_LED_ENABLE)
239 return LED_FULL;
240 else
241 return LED_OFF;
242}
243
244static void
245wbcir_led_brightness_set(struct led_classdev *led_cdev,
246 enum led_brightness brightness)
247{
248 struct wbcir_data *data = container_of(led_cdev,
249 struct wbcir_data,
250 led);
251
252 wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS,
253 brightness == LED_OFF ? 0x00 : WBCIR_LED_ENABLE,
254 WBCIR_LED_ENABLE);
255}
256
257/* Manchester encodes bits to RC6 message cells (see wbcir_shutdown) */
258static u8
259wbcir_to_rc6cells(u8 val)
260{
261 u8 coded = 0x00;
262 int i;
263
264 val &= 0x0F;
265 for (i = 0; i < 4; i++) {
266 if (val & 0x01)
267 coded |= 0x02 << (i * 2);
268 else
269 coded |= 0x01 << (i * 2);
270 val >>= 1;
271 }
272
273 return coded;
274}
275
276/*****************************************************************************
277 *
278 * INTERRUPT FUNCTIONS
279 *
280 *****************************************************************************/
281
282static irqreturn_t
283wbcir_irq_handler(int irqno, void *cookie)
284{
285 struct pnp_dev *device = cookie;
286 struct wbcir_data *data = pnp_get_drvdata(device);
287 unsigned long flags;
288 u8 irdata[8];
289 u8 disable = true;
290 u8 status;
291 int i;
292
293 spin_lock_irqsave(&data->spinlock, flags);
294
295 wbcir_select_bank(data, WBCIR_BANK_0);
296
297 status = inb(data->sbase + WBCIR_REG_SP3_EIR);
298
299 if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) {
300 spin_unlock_irqrestore(&data->spinlock, flags);
301 return IRQ_NONE;
302 }
303
304 /* Check for e.g. buffer overflow */
305 if (status & WBCIR_IRQ_ERR) {
306 data->irdata_error = true;
307 ir_raw_event_reset(data->dev);
308 }
309
310 if (!(status & WBCIR_IRQ_RX))
311 goto out;
312
313 if (!data->irdata_active) {
314 data->irdata_active = true;
315 led_trigger_event(data->rxtrigger, LED_FULL);
316 }
317
318 /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
319 insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8);
320
321 for (i = 0; i < 8; i++) {
322 u8 pulse;
323 u32 duration;
324
325 if (irdata[i] != 0xFF && irdata[i] != 0x00)
326 disable = false;
327
328 if (data->irdata_error)
329 continue;
330
331 pulse = irdata[i] & 0x80 ? false : true;
332 duration = (irdata[i] & 0x7F) * 10000; /* ns */
333
334 if (data->ev.pulse != pulse) {
335 if (data->ev.duration != 0) {
336 ir_raw_event_store(data->dev, &data->ev);
337 data->ev.duration = 0;
338 }
339
340 data->ev.pulse = pulse;
341 }
342
343 data->ev.duration += duration;
344 }
345
346 if (disable) {
347 if (data->ev.duration != 0 && !data->irdata_error) {
348 ir_raw_event_store(data->dev, &data->ev);
349 data->ev.duration = 0;
350 }
351
352 /* Set RXINACTIVE */
353 outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
354
355 /* Drain the FIFO */
356 while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL)
357 inb(data->sbase + WBCIR_REG_SP3_RXDATA);
358
359 ir_raw_event_reset(data->dev);
360 data->irdata_error = false;
361 data->irdata_active = false;
362 led_trigger_event(data->rxtrigger, LED_OFF);
363 }
364
365 ir_raw_event_handle(data->dev);
366
367out:
368 spin_unlock_irqrestore(&data->spinlock, flags);
369 return IRQ_HANDLED;
370}
371
372
373
374/*****************************************************************************
375 *
376 * SETUP/INIT/SUSPEND/RESUME FUNCTIONS
377 *
378 *****************************************************************************/
379
380static void
381wbcir_shutdown(struct pnp_dev *device)
382{
383 struct device *dev = &device->dev;
384 struct wbcir_data *data = pnp_get_drvdata(device);
385 int do_wake = 1;
386 u8 match[11];
387 u8 mask[11];
388 u8 rc6_csl = 0;
389 int i;
390
391 memset(match, 0, sizeof(match));
392 memset(mask, 0, sizeof(mask));
393
394 if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) {
395 do_wake = 0;
396 goto finish;
397 }
398
399 switch (protocol) {
400 case IR_PROTOCOL_RC5:
401 if (wake_sc > 0xFFF) {
402 do_wake = 0;
403 dev_err(dev, "RC5 - Invalid wake scancode\n");
404 break;
405 }
406
407 /* Mask = 13 bits, ex toggle */
408 mask[0] = 0xFF;
409 mask[1] = 0x17;
410
411 match[0] = (wake_sc & 0x003F); /* 6 command bits */
412 match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */
413 match[1] = (wake_sc & 0x0E00) >> 9; /* 3 address bits */
414 if (!(wake_sc & 0x0040)) /* 2nd start bit */
415 match[1] |= 0x10;
416
417 break;
418
419 case IR_PROTOCOL_NEC:
420 if (wake_sc > 0xFFFFFF) {
421 do_wake = 0;
422 dev_err(dev, "NEC - Invalid wake scancode\n");
423 break;
424 }
425
426 mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
427
428 match[1] = bitrev8((wake_sc & 0xFF));
429 match[0] = ~match[1];
430
431 match[3] = bitrev8((wake_sc & 0xFF00) >> 8);
432 if (wake_sc > 0xFFFF)
433 match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
434 else
435 match[2] = ~match[3];
436
437 break;
438
439 case IR_PROTOCOL_RC6:
440
441 if (wake_rc6mode == 0) {
442 if (wake_sc > 0xFFFF) {
443 do_wake = 0;
444 dev_err(dev, "RC6 - Invalid wake scancode\n");
445 break;
446 }
447
448 /* Command */
449 match[0] = wbcir_to_rc6cells(wake_sc >> 0);
450 mask[0] = 0xFF;
451 match[1] = wbcir_to_rc6cells(wake_sc >> 4);
452 mask[1] = 0xFF;
453
454 /* Address */
455 match[2] = wbcir_to_rc6cells(wake_sc >> 8);
456 mask[2] = 0xFF;
457 match[3] = wbcir_to_rc6cells(wake_sc >> 12);
458 mask[3] = 0xFF;
459
460 /* Header */
461 match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */
462 mask[4] = 0xF0;
463 match[5] = 0x09; /* start bit = 1, mode2 = 0 */
464 mask[5] = 0x0F;
465
466 rc6_csl = 44;
467
468 } else if (wake_rc6mode == 6) {
469 i = 0;
470
471 /* Command */
472 match[i] = wbcir_to_rc6cells(wake_sc >> 0);
473 mask[i++] = 0xFF;
474 match[i] = wbcir_to_rc6cells(wake_sc >> 4);
475 mask[i++] = 0xFF;
476
477 /* Address + Toggle */
478 match[i] = wbcir_to_rc6cells(wake_sc >> 8);
479 mask[i++] = 0xFF;
480 match[i] = wbcir_to_rc6cells(wake_sc >> 12);
481 mask[i++] = 0x3F;
482
483 /* Customer bits 7 - 0 */
484 match[i] = wbcir_to_rc6cells(wake_sc >> 16);
485 mask[i++] = 0xFF;
486 match[i] = wbcir_to_rc6cells(wake_sc >> 20);
487 mask[i++] = 0xFF;
488
489 if (wake_sc & 0x80000000) {
490 /* Customer range bit and bits 15 - 8 */
491 match[i] = wbcir_to_rc6cells(wake_sc >> 24);
492 mask[i++] = 0xFF;
493 match[i] = wbcir_to_rc6cells(wake_sc >> 28);
494 mask[i++] = 0xFF;
495 rc6_csl = 76;
496 } else if (wake_sc <= 0x007FFFFF) {
497 rc6_csl = 60;
498 } else {
499 do_wake = 0;
500 dev_err(dev, "RC6 - Invalid wake scancode\n");
501 break;
502 }
503
504 /* Header */
505 match[i] = 0x93; /* mode1 = mode0 = 1, submode = 0 */
506 mask[i++] = 0xFF;
507 match[i] = 0x0A; /* start bit = 1, mode2 = 1 */
508 mask[i++] = 0x0F;
509
510 } else {
511 do_wake = 0;
512 dev_err(dev, "RC6 - Invalid wake mode\n");
513 }
514
515 break;
516
517 default:
518 do_wake = 0;
519 break;
520 }
521
522finish:
523 if (do_wake) {
524 /* Set compare and compare mask */
525 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX,
526 WBCIR_REGSEL_COMPARE | WBCIR_REG_ADDR0,
527 0x3F);
528 outsb(data->wbase + WBCIR_REG_WCEIR_DATA, match, 11);
529 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX,
530 WBCIR_REGSEL_MASK | WBCIR_REG_ADDR0,
531 0x3F);
532 outsb(data->wbase + WBCIR_REG_WCEIR_DATA, mask, 11);
533
534 /* RC6 Compare String Len */
535 outb(rc6_csl, data->wbase + WBCIR_REG_WCEIR_CSL);
536
537 /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
538 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
539
540 /* Clear BUFF_EN, Clear END_EN, Set MATCH_EN */
541 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07);
542
543 /* Set CEIR_EN */
544 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01);
545
546 } else {
547 /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
548 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
549
550 /* Clear CEIR_EN */
551 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
552 }
553
554 /* Disable interrupts */
555 wbcir_select_bank(data, WBCIR_BANK_0);
556 outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
557
558 /* Disable LED */
559 data->irdata_active = false;
560 led_trigger_event(data->rxtrigger, LED_OFF);
561
562 /*
563 * ACPI will set the HW disable bit for SP3 which means that the
564 * output signals are left in an undefined state which may cause
565 * spurious interrupts which we need to ignore until the hardware
566 * is reinitialized.
567 */
568 disable_irq(data->irq);
569}
570
571static int
572wbcir_suspend(struct pnp_dev *device, pm_message_t state)
573{
574 wbcir_shutdown(device);
575 return 0;
576}
577
578static void
579wbcir_init_hw(struct wbcir_data *data)
580{
581 u8 tmp;
582
583 /* Disable interrupts */
584 wbcir_select_bank(data, WBCIR_BANK_0);
585 outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
586
587 /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
588 tmp = protocol << 4;
589 if (invert)
590 tmp |= 0x08;
591 outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL);
592
593 /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
594 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
595
596 /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
597 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
598
599 /* Set RC5 cell time to correspond to 36 kHz */
600 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CFG1, 0x4A, 0x7F);
601
602 /* Set IRTX_INV */
603 if (invert)
604 outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL);
605 else
606 outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL);
607
608 /*
609 * Clear IR LED, set SP3 clock to 24Mhz
610 * set SP3_IRRX_SW to binary 01, helpfully not documented
611 */
612 outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
613
614 /* Enable extended mode */
615 wbcir_select_bank(data, WBCIR_BANK_2);
616 outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
617
618 /*
619 * Configure baud generator, IR data will be sampled at
620 * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
621 *
622 * The ECIR registers include a flag to change the
623 * 24Mhz clock freq to 48Mhz.
624 *
625 * It's not documented in the specs, but fifo levels
626 * other than 16 seems to be unsupported.
627 */
628
629 /* prescaler 1.0, tx/rx fifo lvl 16 */
630 outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
631
632 /* Set baud divisor to generate one byte per bit/cell */
633 switch (protocol) {
634 case IR_PROTOCOL_RC5:
635 outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
636 break;
637 case IR_PROTOCOL_RC6:
638 outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
639 break;
640 case IR_PROTOCOL_NEC:
641 outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
642 break;
643 }
644 outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
645
646 /* Set CEIR mode */
647 wbcir_select_bank(data, WBCIR_BANK_0);
648 outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
649 inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
650 inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
651
652 /* Disable RX demod, run-length encoding/decoding, set freq span */
653 wbcir_select_bank(data, WBCIR_BANK_7);
654 outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
655
656 /* Disable timer */
657 wbcir_select_bank(data, WBCIR_BANK_4);
658 outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
659
660 /* Enable MSR interrupt, Clear AUX_IRX */
661 wbcir_select_bank(data, WBCIR_BANK_5);
662 outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
663
664 /* Disable CRC */
665 wbcir_select_bank(data, WBCIR_BANK_6);
666 outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
667
668 /* Set RX/TX (de)modulation freq, not really used */
669 wbcir_select_bank(data, WBCIR_BANK_7);
670 outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
671 outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
672
673 /* Set invert and pin direction */
674 if (invert)
675 outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
676 else
677 outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
678
679 /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
680 wbcir_select_bank(data, WBCIR_BANK_0);
681 outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
682
683 /* Clear AUX status bits */
684 outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
685
686 /* Clear IR decoding state */
687 data->irdata_active = false;
688 led_trigger_event(data->rxtrigger, LED_OFF);
689 data->irdata_error = false;
690 data->ev.duration = 0;
691 ir_raw_event_reset(data->dev);
692 ir_raw_event_handle(data->dev);
693
694 /* Enable interrupts */
695 outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
696}
697
698static int
699wbcir_resume(struct pnp_dev *device)
700{
701 struct wbcir_data *data = pnp_get_drvdata(device);
702
703 wbcir_init_hw(data);
704 enable_irq(data->irq);
705
706 return 0;
707}
708
709static int __devinit
710wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
711{
712 struct device *dev = &device->dev;
713 struct wbcir_data *data;
714 int err;
715
716 if (!(pnp_port_len(device, 0) == EHFUNC_IOMEM_LEN &&
717 pnp_port_len(device, 1) == WAKEUP_IOMEM_LEN &&
718 pnp_port_len(device, 2) == SP_IOMEM_LEN)) {
719 dev_err(dev, "Invalid resources\n");
720 return -ENODEV;
721 }
722
723 data = kzalloc(sizeof(*data), GFP_KERNEL);
724 if (!data) {
725 err = -ENOMEM;
726 goto exit;
727 }
728
729 pnp_set_drvdata(device, data);
730
731 spin_lock_init(&data->spinlock);
732 data->ebase = pnp_port_start(device, 0);
733 data->wbase = pnp_port_start(device, 1);
734 data->sbase = pnp_port_start(device, 2);
735 data->irq = pnp_irq(device, 0);
736
737 if (data->wbase == 0 || data->ebase == 0 ||
738 data->sbase == 0 || data->irq == 0) {
739 err = -ENODEV;
740 dev_err(dev, "Invalid resources\n");
741 goto exit_free_data;
742 }
743
744 dev_dbg(&device->dev, "Found device "
745 "(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n",
746 data->wbase, data->ebase, data->sbase, data->irq);
747
748 if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) {
749 dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
750 data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1);
751 err = -EBUSY;
752 goto exit_free_data;
753 }
754
755 if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) {
756 dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
757 data->ebase, data->ebase + EHFUNC_IOMEM_LEN - 1);
758 err = -EBUSY;
759 goto exit_release_wbase;
760 }
761
762 if (!request_region(data->sbase, SP_IOMEM_LEN, DRVNAME)) {
763 dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
764 data->sbase, data->sbase + SP_IOMEM_LEN - 1);
765 err = -EBUSY;
766 goto exit_release_ebase;
767 }
768
769 err = request_irq(data->irq, wbcir_irq_handler,
770 IRQF_DISABLED, DRVNAME, device);
771 if (err) {
772 dev_err(dev, "Failed to claim IRQ %u\n", data->irq);
773 err = -EBUSY;
774 goto exit_release_sbase;
775 }
776
777 led_trigger_register_simple("cir-tx", &data->txtrigger);
778 if (!data->txtrigger) {
779 err = -ENOMEM;
780 goto exit_free_irq;
781 }
782
783 led_trigger_register_simple("cir-rx", &data->rxtrigger);
784 if (!data->rxtrigger) {
785 err = -ENOMEM;
786 goto exit_unregister_txtrigger;
787 }
788
789 data->led.name = "cir::activity";
790 data->led.default_trigger = "cir-rx";
791 data->led.brightness_set = wbcir_led_brightness_set;
792 data->led.brightness_get = wbcir_led_brightness_get;
793 err = led_classdev_register(&device->dev, &data->led);
794 if (err)
795 goto exit_unregister_rxtrigger;
796
797 data->dev = rc_allocate_device();
798 if (!data->dev) {
799 err = -ENOMEM;
800 goto exit_unregister_led;
801 }
802
803 data->dev->driver_name = WBCIR_NAME;
804 data->dev->input_name = WBCIR_NAME;
805 data->dev->input_phys = "wbcir/cir0";
806 data->dev->input_id.bustype = BUS_HOST;
807 data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND;
808 data->dev->input_id.product = WBCIR_ID_FAMILY;
809 data->dev->input_id.version = WBCIR_ID_CHIP;
810 data->dev->priv = data;
811 data->dev->dev.parent = &device->dev;
812
813 err = rc_register_device(data->dev);
814 if (err)
815 goto exit_free_rc;
816
817 device_init_wakeup(&device->dev, 1);
818
819 wbcir_init_hw(data);
820
821 return 0;
822
823exit_free_rc:
824 rc_free_device(data->dev);
825exit_unregister_led:
826 led_classdev_unregister(&data->led);
827exit_unregister_rxtrigger:
828 led_trigger_unregister_simple(data->rxtrigger);
829exit_unregister_txtrigger:
830 led_trigger_unregister_simple(data->txtrigger);
831exit_free_irq:
832 free_irq(data->irq, device);
833exit_release_sbase:
834 release_region(data->sbase, SP_IOMEM_LEN);
835exit_release_ebase:
836 release_region(data->ebase, EHFUNC_IOMEM_LEN);
837exit_release_wbase:
838 release_region(data->wbase, WAKEUP_IOMEM_LEN);
839exit_free_data:
840 kfree(data);
841 pnp_set_drvdata(device, NULL);
842exit:
843 return err;
844}
845
846static void __devexit
847wbcir_remove(struct pnp_dev *device)
848{
849 struct wbcir_data *data = pnp_get_drvdata(device);
850
851 /* Disable interrupts */
852 wbcir_select_bank(data, WBCIR_BANK_0);
853 outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
854
855 free_irq(data->irq, device);
856
857 /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
858 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
859
860 /* Clear CEIR_EN */
861 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
862
863 /* Clear BUFF_EN, END_EN, MATCH_EN */
864 wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
865
866 rc_unregister_device(data->dev);
867
868 led_trigger_unregister_simple(data->rxtrigger);
869 led_trigger_unregister_simple(data->txtrigger);
870 led_classdev_unregister(&data->led);
871
872 /* This is ok since &data->led isn't actually used */
873 wbcir_led_brightness_set(&data->led, LED_OFF);
874
875 release_region(data->wbase, WAKEUP_IOMEM_LEN);
876 release_region(data->ebase, EHFUNC_IOMEM_LEN);
877 release_region(data->sbase, SP_IOMEM_LEN);
878
879 kfree(data);
880
881 pnp_set_drvdata(device, NULL);
882}
883
884static const struct pnp_device_id wbcir_ids[] = {
885 { "WEC1022", 0 },
886 { "", 0 }
887};
888MODULE_DEVICE_TABLE(pnp, wbcir_ids);
889
890static struct pnp_driver wbcir_driver = {
891 .name = WBCIR_NAME,
892 .id_table = wbcir_ids,
893 .probe = wbcir_probe,
894 .remove = __devexit_p(wbcir_remove),
895 .suspend = wbcir_suspend,
896 .resume = wbcir_resume,
897 .shutdown = wbcir_shutdown
898};
899
900static int __init
901wbcir_init(void)
902{
903 int ret;
904
905 switch (protocol) {
906 case IR_PROTOCOL_RC5:
907 case IR_PROTOCOL_NEC:
908 case IR_PROTOCOL_RC6:
909 break;
910 default:
911 printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n");
912 }
913
914 ret = pnp_register_driver(&wbcir_driver);
915 if (ret)
916 printk(KERN_ERR DRVNAME ": Unable to register driver\n");
917
918 return ret;
919}
920
921static void __exit
922wbcir_exit(void)
923{
924 pnp_unregister_driver(&wbcir_driver);
925}
926
927module_init(wbcir_init);
928module_exit(wbcir_exit);
929
930MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
931MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver");
932MODULE_LICENSE("GPL");