diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 12:35:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 12:35:11 -0400 |
commit | 0851668fdd97e526b2a41f794b785c204dd3d3e0 (patch) | |
tree | 4ef7c20a8be8393006c6fe9627eb29dd30877d61 /drivers/media/IR | |
parent | 00ebb6382b8d9c7c15b5f8ad230670d8161d38dd (diff) | |
parent | 7655e594945289b418af39f6669fea4666a7b520 (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (505 commits)
[media] af9015: Fix max I2C message size when used with tda18271
[media] IR: initialize ir_raw_event in few more drivers
[media] Guard a divide in v4l1 compat layer
[media] imon: fix nomouse modprobe option
[media] imon: remove redundant change_protocol call
[media] imon: fix my egregious brown paper bag w/rdev/idev split
[media] cafe_ccic: Configure ov7670 correctly
[media] ov7670: allow configuration of image size, clock speed, and I/O method
[media] af9015: support for DigitalNow TinyTwin v3 [1f4d:9016]
[media] af9015: map DigitalNow TinyTwin v2 remote
[media] DigitalNow TinyTwin remote controller
[media] af9015: RC fixes and improvements
videodev2.h.xml: Update to reflect the latest changes at videodev2.h
[media] v4l: document new Bayer and monochrome pixel formats
[media] DocBook/v4l: Add missing formats used on gspca cpia1 and sn9c2028
[media] firedtv: add parameter to fake ca_system_ids in CA_INFO
[media] tm6000: fix a macro coding style issue
tm6000: Remove some ugly debug code
[media] Nova-S-Plus audio line input
[media] [RFC,1/1] V4L2: Use new CAP bits in existing RDS capable drivers
...
Diffstat (limited to 'drivers/media/IR')
40 files changed, 5066 insertions, 1604 deletions
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig index 490c57cc4cfe..aa4163eb7a83 100644 --- a/drivers/media/IR/Kconfig +++ b/drivers/media/IR/Kconfig | |||
@@ -79,6 +79,18 @@ config IR_SONY_DECODER | |||
79 | Enable this option if you have an infrared remote control which | 79 | Enable this option if you have an infrared remote control which |
80 | uses the Sony protocol, and you need software decoding support. | 80 | uses the Sony protocol, and you need software decoding support. |
81 | 81 | ||
82 | config IR_RC5_SZ_DECODER | ||
83 | tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol" | ||
84 | depends on IR_CORE | ||
85 | select BITREVERSE | ||
86 | default y | ||
87 | |||
88 | ---help--- | ||
89 | Enable this option if you have IR with RC-5 (streamzap) protocol, | ||
90 | and if the IR is decoded in software. (The Streamzap PC Remote | ||
91 | uses an IR protocol that is almost standard RC-5, but not quite, | ||
92 | as it uses an additional bit). | ||
93 | |||
82 | config IR_LIRC_CODEC | 94 | config IR_LIRC_CODEC |
83 | tristate "Enable IR to LIRC bridge" | 95 | tristate "Enable IR to LIRC bridge" |
84 | depends on IR_CORE | 96 | depends on IR_CORE |
@@ -89,6 +101,20 @@ config IR_LIRC_CODEC | |||
89 | Enable this option to pass raw IR to and from userspace via | 101 | Enable this option to pass raw IR to and from userspace via |
90 | the LIRC interface. | 102 | the LIRC interface. |
91 | 103 | ||
104 | config IR_ENE | ||
105 | tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" | ||
106 | depends on PNP | ||
107 | depends on IR_CORE | ||
108 | ---help--- | ||
109 | Say Y here to enable support for integrated infrared receiver | ||
110 | /transceiver made by ENE. | ||
111 | |||
112 | You can see if you have it by looking at lspnp output. | ||
113 | Output should include ENE0100 ENE0200 or something similar. | ||
114 | |||
115 | To compile this driver as a module, choose M here: the | ||
116 | module will be called ene_ir. | ||
117 | |||
92 | config IR_IMON | 118 | config IR_IMON |
93 | tristate "SoundGraph iMON Receiver and Display" | 119 | tristate "SoundGraph iMON Receiver and Display" |
94 | depends on USB_ARCH_HAS_HCD | 120 | depends on USB_ARCH_HAS_HCD |
@@ -113,19 +139,18 @@ config IR_MCEUSB | |||
113 | To compile this driver as a module, choose M here: the | 139 | To compile this driver as a module, choose M here: the |
114 | module will be called mceusb. | 140 | module will be called mceusb. |
115 | 141 | ||
116 | config IR_ENE | 142 | config IR_NUVOTON |
117 | tristate "ENE eHome Receiver/Transciever (pnp id: ENE0100/ENE02xxx)" | 143 | tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" |
118 | depends on PNP | 144 | depends on PNP |
119 | depends on IR_CORE | 145 | depends on IR_CORE |
120 | ---help--- | 146 | ---help--- |
121 | Say Y here to enable support for integrated infrared receiver | 147 | Say Y here to enable support for integrated infrared receiver |
122 | /transciever made by ENE. | 148 | /transciever made by Nuvoton (formerly Winbond). This chip is |
123 | 149 | found in the ASRock ION 330HT, as well as assorted Intel | |
124 | You can see if you have it by looking at lspnp output. | 150 | DP55-series motherboards (and of course, possibly others). |
125 | Output should include ENE0100 ENE0200 or something similiar. | ||
126 | 151 | ||
127 | To compile this driver as a module, choose M here: the | 152 | To compile this driver as a module, choose M here: the |
128 | module will be called ene_ir. | 153 | module will be called nuvoton-cir. |
129 | 154 | ||
130 | config IR_STREAMZAP | 155 | config IR_STREAMZAP |
131 | tristate "Streamzap PC Remote IR Receiver" | 156 | tristate "Streamzap PC Remote IR Receiver" |
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile index 53676838fe97..f9574adab82a 100644 --- a/drivers/media/IR/Makefile +++ b/drivers/media/IR/Makefile | |||
@@ -11,10 +11,12 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o | |||
11 | obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o | 11 | obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o |
12 | obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o | 12 | obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o |
13 | obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o | 13 | obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o |
14 | obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o | ||
14 | obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o | 15 | obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o |
15 | 16 | ||
16 | # stand-alone IR receivers/transmitters | 17 | # stand-alone IR receivers/transmitters |
17 | obj-$(CONFIG_IR_IMON) += imon.o | 18 | obj-$(CONFIG_IR_IMON) += imon.o |
18 | obj-$(CONFIG_IR_MCEUSB) += mceusb.o | 19 | obj-$(CONFIG_IR_MCEUSB) += mceusb.o |
20 | obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o | ||
19 | obj-$(CONFIG_IR_ENE) += ene_ir.o | 21 | obj-$(CONFIG_IR_ENE) += ene_ir.o |
20 | obj-$(CONFIG_IR_STREAMZAP) += streamzap.o | 22 | obj-$(CONFIG_IR_STREAMZAP) += streamzap.o |
diff --git a/drivers/media/IR/ene_ir.c b/drivers/media/IR/ene_ir.c index 5447750f5e38..7637babcd262 100644 --- a/drivers/media/IR/ene_ir.c +++ b/drivers/media/IR/ene_ir.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX) | 2 | * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX) |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com> | 4 | * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com> |
5 | * | 5 | * |
@@ -17,6 +17,17 @@ | |||
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
19 | * USA | 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 | * | ||
20 | */ | 31 | */ |
21 | 32 | ||
22 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
@@ -31,51 +42,59 @@ | |||
31 | #include <media/ir-common.h> | 42 | #include <media/ir-common.h> |
32 | #include "ene_ir.h" | 43 | #include "ene_ir.h" |
33 | 44 | ||
34 | 45 | static int sample_period; | |
35 | static int sample_period = -1; | 46 | static bool learning_mode_force; |
36 | static int enable_idle = 1; | ||
37 | static int input = 1; | ||
38 | static int debug; | 47 | static int debug; |
39 | static int txsim; | 48 | static bool txsim; |
40 | 49 | ||
41 | static int ene_irq_status(struct ene_device *dev); | 50 | static void ene_set_reg_addr(struct ene_device *dev, u16 reg) |
51 | { | ||
52 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | ||
53 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | ||
54 | } | ||
42 | 55 | ||
43 | /* read a hardware register */ | 56 | /* read a hardware register */ |
44 | static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) | 57 | static u8 ene_read_reg(struct ene_device *dev, u16 reg) |
45 | { | 58 | { |
46 | u8 retval; | 59 | u8 retval; |
47 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | 60 | ene_set_reg_addr(dev, reg); |
48 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | ||
49 | retval = inb(dev->hw_io + ENE_IO); | 61 | retval = inb(dev->hw_io + ENE_IO); |
50 | 62 | dbg_regs("reg %04x == %02x", reg, retval); | |
51 | ene_dbg_verbose("reg %04x == %02x", reg, retval); | ||
52 | return retval; | 63 | return retval; |
53 | } | 64 | } |
54 | 65 | ||
55 | /* write a hardware register */ | 66 | /* write a hardware register */ |
56 | static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value) | 67 | static void ene_write_reg(struct ene_device *dev, u16 reg, u8 value) |
57 | { | 68 | { |
58 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | 69 | dbg_regs("reg %04x <- %02x", reg, value); |
59 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | 70 | ene_set_reg_addr(dev, reg); |
60 | outb(value, dev->hw_io + ENE_IO); | 71 | outb(value, dev->hw_io + ENE_IO); |
61 | |||
62 | ene_dbg_verbose("reg %04x <- %02x", reg, value); | ||
63 | } | 72 | } |
64 | 73 | ||
65 | /* change specific bits in hardware register */ | 74 | /* Set bits in hardware register */ |
66 | static void ene_hw_write_reg_mask(struct ene_device *dev, | 75 | static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask) |
67 | u16 reg, u8 value, u8 mask) | ||
68 | { | 76 | { |
69 | u8 regvalue; | 77 | dbg_regs("reg %04x |= %02x", reg, mask); |
70 | 78 | ene_set_reg_addr(dev, reg); | |
71 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | 79 | outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO); |
72 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | 80 | } |
73 | 81 | ||
74 | regvalue = inb(dev->hw_io + ENE_IO) & ~mask; | 82 | /* Clear bits in hardware register */ |
75 | regvalue |= (value & mask); | 83 | static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask) |
76 | outb(regvalue, dev->hw_io + ENE_IO); | 84 | { |
85 | dbg_regs("reg %04x &= ~%02x ", reg, mask); | ||
86 | ene_set_reg_addr(dev, reg); | ||
87 | outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO); | ||
88 | } | ||
77 | 89 | ||
78 | ene_dbg_verbose("reg %04x <- %02x (mask=%02x)", reg, value, mask); | 90 | /* A helper to set/clear a bit in register according to boolean variable */ |
91 | static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask, | ||
92 | bool set) | ||
93 | { | ||
94 | if (set) | ||
95 | ene_set_reg_mask(dev, reg, mask); | ||
96 | else | ||
97 | ene_clear_reg_mask(dev, reg, mask); | ||
79 | } | 98 | } |
80 | 99 | ||
81 | /* detect hardware features */ | 100 | /* detect hardware features */ |
@@ -83,194 +102,378 @@ static int ene_hw_detect(struct ene_device *dev) | |||
83 | { | 102 | { |
84 | u8 chip_major, chip_minor; | 103 | u8 chip_major, chip_minor; |
85 | u8 hw_revision, old_ver; | 104 | u8 hw_revision, old_ver; |
86 | u8 tmp; | 105 | u8 fw_reg2, fw_reg1; |
87 | u8 fw_capabilities; | ||
88 | int pll_freq; | ||
89 | 106 | ||
90 | tmp = ene_hw_read_reg(dev, ENE_HW_UNK); | 107 | ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD); |
91 | ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR); | 108 | chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR); |
109 | chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR); | ||
110 | ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD); | ||
92 | 111 | ||
93 | chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR); | 112 | hw_revision = ene_read_reg(dev, ENE_ECHV); |
94 | chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR); | 113 | old_ver = ene_read_reg(dev, ENE_HW_VER_OLD); |
95 | 114 | ||
96 | ene_hw_write_reg(dev, ENE_HW_UNK, tmp); | 115 | dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) + |
97 | hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION); | 116 | (ene_read_reg(dev, ENE_PLLFRL) >> 4); |
98 | old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD); | ||
99 | 117 | ||
100 | pll_freq = (ene_hw_read_reg(dev, ENE_PLLFRH) << 4) + | 118 | if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD) |
101 | (ene_hw_read_reg(dev, ENE_PLLFRL) >> 4); | 119 | dev->rx_period_adjust = |
102 | 120 | dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4; | |
103 | if (pll_freq != 1000) | ||
104 | dev->rx_period_adjust = 4; | ||
105 | else | ||
106 | dev->rx_period_adjust = 2; | ||
107 | |||
108 | |||
109 | ene_printk(KERN_NOTICE, "PLL freq = %d\n", pll_freq); | ||
110 | 121 | ||
111 | if (hw_revision == 0xFF) { | 122 | if (hw_revision == 0xFF) { |
112 | 123 | ene_warn("device seems to be disabled"); | |
113 | ene_printk(KERN_WARNING, "device seems to be disabled\n"); | 124 | ene_warn("send a mail to lirc-list@lists.sourceforge.net"); |
114 | ene_printk(KERN_WARNING, | 125 | ene_warn("please attach output of acpidump and dmidecode"); |
115 | "send a mail to lirc-list@lists.sourceforge.net\n"); | ||
116 | ene_printk(KERN_WARNING, "please attach output of acpidump\n"); | ||
117 | return -ENODEV; | 126 | return -ENODEV; |
118 | } | 127 | } |
119 | 128 | ||
129 | ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x", | ||
130 | chip_major, chip_minor, old_ver, hw_revision); | ||
131 | |||
132 | ene_notice("PLL freq = %d", dev->pll_freq); | ||
133 | |||
120 | if (chip_major == 0x33) { | 134 | if (chip_major == 0x33) { |
121 | ene_printk(KERN_WARNING, "chips 0x33xx aren't supported\n"); | 135 | ene_warn("chips 0x33xx aren't supported"); |
122 | return -ENODEV; | 136 | return -ENODEV; |
123 | } | 137 | } |
124 | 138 | ||
125 | if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { | 139 | if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { |
126 | dev->hw_revision = ENE_HW_C; | 140 | dev->hw_revision = ENE_HW_C; |
141 | ene_notice("KB3926C detected"); | ||
127 | } else if (old_ver == 0x24 && hw_revision == 0xC0) { | 142 | } else if (old_ver == 0x24 && hw_revision == 0xC0) { |
128 | dev->hw_revision = ENE_HW_B; | 143 | dev->hw_revision = ENE_HW_B; |
129 | ene_printk(KERN_NOTICE, "KB3926B detected\n"); | 144 | ene_notice("KB3926B detected"); |
130 | } else { | 145 | } else { |
131 | dev->hw_revision = ENE_HW_D; | 146 | dev->hw_revision = ENE_HW_D; |
132 | ene_printk(KERN_WARNING, | 147 | ene_notice("KB3926D or higher detected"); |
133 | "unknown ENE chip detected, assuming KB3926D\n"); | ||
134 | ene_printk(KERN_WARNING, | ||
135 | "driver support might be not complete"); | ||
136 | |||
137 | } | 148 | } |
138 | 149 | ||
139 | ene_printk(KERN_DEBUG, | ||
140 | "chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n", | ||
141 | chip_major, chip_minor, old_ver, hw_revision); | ||
142 | |||
143 | /* detect features hardware supports */ | 150 | /* detect features hardware supports */ |
144 | if (dev->hw_revision < ENE_HW_C) | 151 | if (dev->hw_revision < ENE_HW_C) |
145 | return 0; | 152 | return 0; |
146 | 153 | ||
147 | fw_capabilities = ene_hw_read_reg(dev, ENE_FW2); | 154 | fw_reg1 = ene_read_reg(dev, ENE_FW1); |
148 | ene_dbg("Firmware capabilities: %02x", fw_capabilities); | 155 | fw_reg2 = ene_read_reg(dev, ENE_FW2); |
156 | |||
157 | ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2); | ||
149 | 158 | ||
150 | dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; | 159 | dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A); |
151 | dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; | 160 | dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING); |
161 | dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF); | ||
152 | 162 | ||
153 | dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && | 163 | if (dev->hw_learning_and_tx_capable) |
154 | (fw_capabilities & ENE_FW2_FAN_AS_NRML_IN); | 164 | dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT); |
155 | 165 | ||
156 | ene_printk(KERN_NOTICE, "hardware features:\n"); | 166 | ene_notice("Hardware features:"); |
157 | ene_printk(KERN_NOTICE, | ||
158 | "learning and transmit %s, gpio40_learn %s, fan_in %s\n", | ||
159 | dev->hw_learning_and_tx_capable ? "on" : "off", | ||
160 | dev->hw_gpio40_learning ? "on" : "off", | ||
161 | dev->hw_fan_as_normal_input ? "on" : "off"); | ||
162 | 167 | ||
163 | if (dev->hw_learning_and_tx_capable) { | 168 | if (dev->hw_learning_and_tx_capable) { |
164 | ene_printk(KERN_WARNING, | 169 | ene_notice("* Supports transmitting & learning mode"); |
165 | "Device supports transmitting, but that support is\n"); | 170 | ene_notice(" This feature is rare and therefore,"); |
166 | ene_printk(KERN_WARNING, | 171 | ene_notice(" you are welcome to test it,"); |
167 | "lightly tested. Please test it and mail\n"); | 172 | ene_notice(" and/or contact the author via:"); |
168 | ene_printk(KERN_WARNING, | 173 | ene_notice(" lirc-list@lists.sourceforge.net"); |
169 | "lirc-list@lists.sourceforge.net\n"); | 174 | ene_notice(" or maximlevitsky@gmail.com"); |
175 | |||
176 | ene_notice("* Uses GPIO %s for IR raw input", | ||
177 | dev->hw_use_gpio_0a ? "40" : "0A"); | ||
178 | |||
179 | if (dev->hw_fan_input) | ||
180 | ene_notice("* Uses unused fan feedback input as source" | ||
181 | " of demodulated IR data"); | ||
170 | } | 182 | } |
183 | |||
184 | if (!dev->hw_fan_input) | ||
185 | ene_notice("* Uses GPIO %s for IR demodulated input", | ||
186 | dev->hw_use_gpio_0a ? "0A" : "40"); | ||
187 | |||
188 | if (dev->hw_extra_buffer) | ||
189 | ene_notice("* Uses new style input buffer"); | ||
171 | return 0; | 190 | return 0; |
172 | } | 191 | } |
173 | 192 | ||
174 | /* this enables/disables IR input via gpio40*/ | 193 | /* Read properities of hw sample buffer */ |
175 | static void ene_enable_gpio40_receive(struct ene_device *dev, int enable) | 194 | static void ene_rx_setup_hw_buffer(struct ene_device *dev) |
176 | { | 195 | { |
177 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ? | 196 | u16 tmp; |
178 | 0 : ENE_CIR_CONF2_GPIO40DIS, | 197 | |
179 | ENE_CIR_CONF2_GPIO40DIS); | 198 | ene_rx_read_hw_pointer(dev); |
199 | dev->r_pointer = dev->w_pointer; | ||
200 | |||
201 | if (!dev->hw_extra_buffer) { | ||
202 | dev->buffer_len = ENE_FW_PACKET_SIZE * 2; | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER); | ||
207 | tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8; | ||
208 | dev->extra_buf1_address = tmp; | ||
209 | |||
210 | dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2); | ||
211 | |||
212 | tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3); | ||
213 | tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8; | ||
214 | dev->extra_buf2_address = tmp; | ||
215 | |||
216 | dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5); | ||
217 | |||
218 | dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8; | ||
219 | |||
220 | ene_notice("Hardware uses 2 extended buffers:"); | ||
221 | ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address, | ||
222 | dev->extra_buf1_len); | ||
223 | ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address, | ||
224 | dev->extra_buf2_len); | ||
225 | |||
226 | ene_notice("Total buffer len = %d", dev->buffer_len); | ||
227 | |||
228 | if (dev->buffer_len > 64 || dev->buffer_len < 16) | ||
229 | goto error; | ||
230 | |||
231 | if (dev->extra_buf1_address > 0xFBFC || | ||
232 | dev->extra_buf1_address < 0xEC00) | ||
233 | goto error; | ||
234 | |||
235 | if (dev->extra_buf2_address > 0xFBFC || | ||
236 | dev->extra_buf2_address < 0xEC00) | ||
237 | goto error; | ||
238 | |||
239 | if (dev->r_pointer > dev->buffer_len) | ||
240 | goto error; | ||
241 | |||
242 | ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); | ||
243 | return; | ||
244 | error: | ||
245 | ene_warn("Error validating extra buffers, device probably won't work"); | ||
246 | dev->hw_extra_buffer = false; | ||
247 | ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); | ||
180 | } | 248 | } |
181 | 249 | ||
182 | /* this enables/disables IR via standard input */ | 250 | |
183 | static void ene_enable_normal_receive(struct ene_device *dev, int enable) | 251 | /* Restore the pointers to extra buffers - to make module reload work*/ |
252 | static void ene_rx_restore_hw_buffer(struct ene_device *dev) | ||
184 | { | 253 | { |
185 | ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0); | 254 | if (!dev->hw_extra_buffer) |
255 | return; | ||
256 | |||
257 | ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0, | ||
258 | dev->extra_buf1_address & 0xFF); | ||
259 | ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1, | ||
260 | dev->extra_buf1_address >> 8); | ||
261 | ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len); | ||
262 | |||
263 | ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3, | ||
264 | dev->extra_buf2_address & 0xFF); | ||
265 | ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4, | ||
266 | dev->extra_buf2_address >> 8); | ||
267 | ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5, | ||
268 | dev->extra_buf2_len); | ||
269 | ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND); | ||
186 | } | 270 | } |
187 | 271 | ||
188 | /* this enables/disables IR input via unused fan tachtometer input */ | 272 | /* Read hardware write pointer */ |
189 | static void ene_enable_fan_receive(struct ene_device *dev, int enable) | 273 | static void ene_rx_read_hw_pointer(struct ene_device *dev) |
190 | { | 274 | { |
191 | if (!enable) | 275 | if (dev->hw_extra_buffer) |
192 | ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); | 276 | dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER); |
193 | else { | 277 | else |
194 | ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); | 278 | dev->w_pointer = ene_read_reg(dev, ENE_FW2) |
195 | ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); | 279 | & ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE; |
196 | } | 280 | |
197 | dev->rx_fan_input_inuse = enable; | 281 | dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x", |
282 | dev->w_pointer, dev->r_pointer); | ||
198 | } | 283 | } |
199 | 284 | ||
285 | /* Gets address of next sample from HW ring buffer */ | ||
286 | static int ene_rx_get_sample_reg(struct ene_device *dev) | ||
287 | { | ||
288 | int r_pointer; | ||
289 | |||
290 | if (dev->r_pointer == dev->w_pointer) { | ||
291 | dbg_verbose("RB: hit end, try update w_pointer"); | ||
292 | ene_rx_read_hw_pointer(dev); | ||
293 | } | ||
294 | |||
295 | if (dev->r_pointer == dev->w_pointer) { | ||
296 | dbg_verbose("RB: end of data at %d", dev->r_pointer); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | dbg_verbose("RB: reading at offset %d", dev->r_pointer); | ||
301 | r_pointer = dev->r_pointer; | ||
302 | |||
303 | dev->r_pointer++; | ||
304 | if (dev->r_pointer == dev->buffer_len) | ||
305 | dev->r_pointer = 0; | ||
306 | |||
307 | dbg_verbose("RB: next read will be from offset %d", dev->r_pointer); | ||
308 | |||
309 | if (r_pointer < 8) { | ||
310 | dbg_verbose("RB: read at main buffer at %d", r_pointer); | ||
311 | return ENE_FW_SAMPLE_BUFFER + r_pointer; | ||
312 | } | ||
313 | |||
314 | r_pointer -= 8; | ||
315 | |||
316 | if (r_pointer < dev->extra_buf1_len) { | ||
317 | dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer); | ||
318 | return dev->extra_buf1_address + r_pointer; | ||
319 | } | ||
320 | |||
321 | r_pointer -= dev->extra_buf1_len; | ||
322 | |||
323 | if (r_pointer < dev->extra_buf2_len) { | ||
324 | dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer); | ||
325 | return dev->extra_buf2_address + r_pointer; | ||
326 | } | ||
327 | |||
328 | dbg("attempt to read beyong ring bufer end"); | ||
329 | return 0; | ||
330 | } | ||
200 | 331 | ||
201 | /* Sense current received carrier */ | 332 | /* Sense current received carrier */ |
202 | static int ene_rx_sense_carrier(struct ene_device *dev) | 333 | void ene_rx_sense_carrier(struct ene_device *dev) |
203 | { | 334 | { |
204 | int period = ene_hw_read_reg(dev, ENE_RX_CARRIER); | 335 | DEFINE_IR_RAW_EVENT(ev); |
205 | int carrier; | ||
206 | ene_dbg("RX: hardware carrier period = %02x", period); | ||
207 | 336 | ||
208 | if (!(period & ENE_RX_CARRIER_VALID)) | 337 | int carrier, duty_cycle; |
209 | return 0; | 338 | int period = ene_read_reg(dev, ENE_CIRCAR_PRD); |
339 | int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD); | ||
340 | |||
341 | if (!(period & ENE_CIRCAR_PRD_VALID)) | ||
342 | return; | ||
210 | 343 | ||
211 | period &= ~ENE_RX_CARRIER_VALID; | 344 | period &= ~ENE_CIRCAR_PRD_VALID; |
212 | 345 | ||
213 | if (!period) | 346 | if (!period) |
214 | return 0; | 347 | return; |
348 | |||
349 | dbg("RX: hardware carrier period = %02x", period); | ||
350 | dbg("RX: hardware carrier pulse period = %02x", hperiod); | ||
215 | 351 | ||
216 | carrier = 2000000 / period; | 352 | carrier = 2000000 / period; |
217 | ene_dbg("RX: sensed carrier = %d Hz", carrier); | 353 | duty_cycle = (hperiod * 100) / period; |
218 | return carrier; | 354 | dbg("RX: sensed carrier = %d Hz, duty cycle %d%%", |
355 | carrier, duty_cycle); | ||
356 | if (dev->carrier_detect_enabled) { | ||
357 | ev.carrier_report = true; | ||
358 | ev.carrier = carrier; | ||
359 | ev.duty_cycle = duty_cycle; | ||
360 | ir_raw_event_store(dev->idev, &ev); | ||
361 | } | ||
219 | } | 362 | } |
220 | 363 | ||
221 | /* determine which input to use*/ | 364 | /* this enables/disables the CIR RX engine */ |
222 | static void ene_rx_set_inputs(struct ene_device *dev) | 365 | static void ene_rx_enable_cir_engine(struct ene_device *dev, bool enable) |
223 | { | 366 | { |
224 | int learning_mode = dev->learning_enabled; | 367 | ene_set_clear_reg_mask(dev, ENE_CIRCFG, |
225 | 368 | ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable); | |
226 | ene_dbg("RX: setup receiver, learning mode = %d", learning_mode); | 369 | } |
227 | 370 | ||
228 | ene_enable_normal_receive(dev, 1); | 371 | /* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/ |
372 | static void ene_rx_select_input(struct ene_device *dev, bool gpio_0a) | ||
373 | { | ||
374 | ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a); | ||
375 | } | ||
229 | 376 | ||
230 | /* old hardware doesn't support learning mode for sure */ | 377 | /* |
231 | if (dev->hw_revision <= ENE_HW_B) | 378 | * this enables alternative input via fan tachometer sensor and bypasses |
379 | * the hw CIR engine | ||
380 | */ | ||
381 | static void ene_rx_enable_fan_input(struct ene_device *dev, bool enable) | ||
382 | { | ||
383 | if (!dev->hw_fan_input) | ||
232 | return; | 384 | return; |
233 | 385 | ||
234 | /* receiver not learning capable, still set gpio40 correctly */ | 386 | if (!enable) |
235 | if (!dev->hw_learning_and_tx_capable) { | 387 | ene_write_reg(dev, ENE_FAN_AS_IN1, 0); |
236 | ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning); | 388 | else { |
237 | return; | 389 | ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); |
390 | ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); | ||
238 | } | 391 | } |
392 | } | ||
393 | |||
394 | /* setup the receiver for RX*/ | ||
395 | static void ene_rx_setup(struct ene_device *dev) | ||
396 | { | ||
397 | bool learning_mode = dev->learning_mode_enabled || | ||
398 | dev->carrier_detect_enabled; | ||
399 | int sample_period_adjust = 0; | ||
400 | |||
401 | dbg("RX: setup receiver, learning mode = %d", learning_mode); | ||
402 | |||
403 | |||
404 | /* This selects RLC input and clears CFG2 settings */ | ||
405 | ene_write_reg(dev, ENE_CIRCFG2, 0x00); | ||
406 | |||
407 | /* set sample period*/ | ||
408 | if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD) | ||
409 | sample_period_adjust = | ||
410 | dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2; | ||
411 | |||
412 | ene_write_reg(dev, ENE_CIRRLC_CFG, | ||
413 | (sample_period + sample_period_adjust) | | ||
414 | ENE_CIRRLC_CFG_OVERFLOW); | ||
415 | /* revB doesn't support inputs */ | ||
416 | if (dev->hw_revision < ENE_HW_C) | ||
417 | goto select_timeout; | ||
239 | 418 | ||
240 | /* enable learning mode */ | ||
241 | if (learning_mode) { | 419 | if (learning_mode) { |
242 | ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning); | ||
243 | 420 | ||
244 | /* fan input is not used for learning */ | 421 | WARN_ON(!dev->hw_learning_and_tx_capable); |
245 | if (dev->hw_fan_as_normal_input) | ||
246 | ene_enable_fan_receive(dev, 0); | ||
247 | 422 | ||
248 | /* disable learning mode */ | 423 | /* Enable the opposite of the normal input |
249 | } else { | 424 | That means that if GPIO40 is normally used, use GPIO0A |
250 | if (dev->hw_fan_as_normal_input) { | 425 | and vice versa. |
251 | ene_enable_fan_receive(dev, 1); | 426 | This input will carry non demodulated |
252 | ene_enable_normal_receive(dev, 0); | 427 | signal, and we will tell the hw to demodulate it itself */ |
253 | } else | 428 | ene_rx_select_input(dev, !dev->hw_use_gpio_0a); |
254 | ene_enable_gpio40_receive(dev, | 429 | dev->rx_fan_input_inuse = false; |
255 | !dev->hw_gpio40_learning); | ||
256 | } | ||
257 | 430 | ||
258 | /* set few additional settings for this mode */ | 431 | /* Enable carrier demodulation */ |
259 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_mode ? | 432 | ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD); |
260 | ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); | ||
261 | 433 | ||
262 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ? | 434 | /* Enable carrier detection */ |
263 | ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); | 435 | ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63); |
436 | ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT, | ||
437 | dev->carrier_detect_enabled || debug); | ||
438 | } else { | ||
439 | if (dev->hw_fan_input) | ||
440 | dev->rx_fan_input_inuse = true; | ||
441 | else | ||
442 | ene_rx_select_input(dev, dev->hw_use_gpio_0a); | ||
443 | |||
444 | /* Disable carrier detection & demodulation */ | ||
445 | ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD); | ||
446 | ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT); | ||
447 | } | ||
264 | 448 | ||
449 | select_timeout: | ||
265 | if (dev->rx_fan_input_inuse) { | 450 | if (dev->rx_fan_input_inuse) { |
266 | dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000; | 451 | dev->props->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN); |
267 | 452 | ||
268 | dev->props->timeout = | 453 | /* Fan input doesn't support timeouts, it just ends the |
269 | ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000; | 454 | input with a maximum sample */ |
455 | dev->props->min_timeout = dev->props->max_timeout = | ||
456 | MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK * | ||
457 | ENE_FW_SAMPLE_PERIOD_FAN); | ||
270 | } else { | 458 | } else { |
271 | dev->props->rx_resolution = sample_period * 1000; | 459 | dev->props->rx_resolution = MS_TO_NS(sample_period); |
272 | dev->props->timeout = ENE_MAXGAP * 1000; | 460 | |
461 | /* Theoreticly timeout is unlimited, but we cap it | ||
462 | * because it was seen that on one device, it | ||
463 | * would stop sending spaces after around 250 msec. | ||
464 | * Besides, this is close to 2^32 anyway and timeout is u32. | ||
465 | */ | ||
466 | dev->props->min_timeout = MS_TO_NS(127 * sample_period); | ||
467 | dev->props->max_timeout = MS_TO_NS(200000); | ||
273 | } | 468 | } |
469 | |||
470 | if (dev->hw_learning_and_tx_capable) | ||
471 | dev->props->tx_resolution = MS_TO_NS(sample_period); | ||
472 | |||
473 | if (dev->props->timeout > dev->props->max_timeout) | ||
474 | dev->props->timeout = dev->props->max_timeout; | ||
475 | if (dev->props->timeout < dev->props->min_timeout) | ||
476 | dev->props->timeout = dev->props->min_timeout; | ||
274 | } | 477 | } |
275 | 478 | ||
276 | /* Enable the device for receive */ | 479 | /* Enable the device for receive */ |
@@ -278,145 +481,157 @@ static void ene_rx_enable(struct ene_device *dev) | |||
278 | { | 481 | { |
279 | u8 reg_value; | 482 | u8 reg_value; |
280 | 483 | ||
484 | /* Enable system interrupt */ | ||
281 | if (dev->hw_revision < ENE_HW_C) { | 485 | if (dev->hw_revision < ENE_HW_C) { |
282 | ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1); | 486 | ene_write_reg(dev, ENEB_IRQ, dev->irq << 1); |
283 | ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01); | 487 | ene_write_reg(dev, ENEB_IRQ_UNK1, 0x01); |
284 | } else { | 488 | } else { |
285 | reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0; | 489 | reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0; |
286 | reg_value |= ENEC_IRQ_UNK_EN; | 490 | reg_value |= ENE_IRQ_UNK_EN; |
287 | reg_value &= ~ENEC_IRQ_STATUS; | 491 | reg_value &= ~ENE_IRQ_STATUS; |
288 | reg_value |= (dev->irq & ENEC_IRQ_MASK); | 492 | reg_value |= (dev->irq & ENE_IRQ_MASK); |
289 | ene_hw_write_reg(dev, ENEC_IRQ, reg_value); | 493 | ene_write_reg(dev, ENE_IRQ, reg_value); |
290 | ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63); | ||
291 | } | 494 | } |
292 | 495 | ||
293 | ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); | 496 | /* Enable inputs */ |
294 | ene_rx_set_inputs(dev); | 497 | ene_rx_enable_fan_input(dev, dev->rx_fan_input_inuse); |
295 | 498 | ene_rx_enable_cir_engine(dev, !dev->rx_fan_input_inuse); | |
296 | /* set sampling period */ | ||
297 | ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); | ||
298 | 499 | ||
299 | /* ack any pending irqs - just in case */ | 500 | /* ack any pending irqs - just in case */ |
300 | ene_irq_status(dev); | 501 | ene_irq_status(dev); |
301 | 502 | ||
302 | /* enable firmware bits */ | 503 | /* enable firmware bits */ |
303 | ene_hw_write_reg_mask(dev, ENE_FW1, | 504 | ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ); |
304 | ENE_FW1_ENABLE | ENE_FW1_IRQ, | ||
305 | ENE_FW1_ENABLE | ENE_FW1_IRQ); | ||
306 | 505 | ||
307 | /* enter idle mode */ | 506 | /* enter idle mode */ |
308 | ir_raw_event_set_idle(dev->idev, 1); | 507 | ir_raw_event_set_idle(dev->idev, true); |
309 | ir_raw_event_reset(dev->idev); | 508 | dev->rx_enabled = true; |
310 | |||
311 | } | 509 | } |
312 | 510 | ||
313 | /* Disable the device receiver */ | 511 | /* Disable the device receiver */ |
314 | static void ene_rx_disable(struct ene_device *dev) | 512 | static void ene_rx_disable(struct ene_device *dev) |
315 | { | 513 | { |
316 | /* disable inputs */ | 514 | /* disable inputs */ |
317 | ene_enable_normal_receive(dev, 0); | 515 | ene_rx_enable_cir_engine(dev, false); |
318 | 516 | ene_rx_enable_fan_input(dev, false); | |
319 | if (dev->hw_fan_as_normal_input) | ||
320 | ene_enable_fan_receive(dev, 0); | ||
321 | 517 | ||
322 | /* disable hardware IRQ and firmware flag */ | 518 | /* disable hardware IRQ and firmware flag */ |
323 | ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); | 519 | ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ); |
324 | 520 | ||
325 | ir_raw_event_set_idle(dev->idev, 1); | 521 | ir_raw_event_set_idle(dev->idev, true); |
326 | ir_raw_event_reset(dev->idev); | 522 | dev->rx_enabled = false; |
327 | } | 523 | } |
328 | 524 | ||
525 | /* This resets the receiver. Usefull to stop stream of spaces at end of | ||
526 | * transmission | ||
527 | */ | ||
528 | static void ene_rx_reset(struct ene_device *dev) | ||
529 | { | ||
530 | ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN); | ||
531 | ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN); | ||
532 | } | ||
329 | 533 | ||
330 | /* prepare transmission */ | 534 | /* Set up the TX carrier frequency and duty cycle */ |
331 | static void ene_tx_prepare(struct ene_device *dev) | 535 | static void ene_tx_set_carrier(struct ene_device *dev) |
332 | { | 536 | { |
333 | u8 conf1; | 537 | u8 tx_puls_width; |
538 | unsigned long flags; | ||
334 | 539 | ||
335 | conf1 = ene_hw_read_reg(dev, ENE_CIR_CONF1); | 540 | spin_lock_irqsave(&dev->hw_lock, flags); |
336 | dev->saved_conf1 = conf1; | ||
337 | 541 | ||
338 | if (dev->hw_revision == ENE_HW_C) | 542 | ene_set_clear_reg_mask(dev, ENE_CIRCFG, |
339 | conf1 &= ~ENE_CIR_CONF1_TX_CLEAR; | 543 | ENE_CIRCFG_TX_CARR, dev->tx_period > 0); |
340 | 544 | ||
341 | /* Enable TX engine */ | 545 | if (!dev->tx_period) |
342 | conf1 |= ENE_CIR_CONF1_TX_ON; | 546 | goto unlock; |
343 | 547 | ||
344 | /* Set carrier */ | 548 | BUG_ON(dev->tx_duty_cycle >= 100 || dev->tx_duty_cycle <= 0); |
345 | if (dev->tx_period) { | ||
346 | 549 | ||
347 | /* NOTE: duty cycle handling is just a guess, it might | 550 | tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle); |
348 | not be aviable. Default values were tested */ | ||
349 | int tx_period_in500ns = dev->tx_period * 2; | ||
350 | 551 | ||
351 | int tx_pulse_width_in_500ns = | 552 | if (!tx_puls_width) |
352 | tx_period_in500ns / (100 / dev->tx_duty_cycle); | 553 | tx_puls_width = 1; |
353 | 554 | ||
354 | if (!tx_pulse_width_in_500ns) | 555 | dbg("TX: pulse distance = %d * 500 ns", dev->tx_period); |
355 | tx_pulse_width_in_500ns = 1; | 556 | dbg("TX: pulse width = %d * 500 ns", tx_puls_width); |
356 | 557 | ||
357 | ene_dbg("TX: pulse distance = %d * 500 ns", tx_period_in500ns); | 558 | ene_write_reg(dev, ENE_CIRMOD_PRD, dev->tx_period | ENE_CIRMOD_PRD_POL); |
358 | ene_dbg("TX: pulse width = %d * 500 ns", | 559 | ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width); |
359 | tx_pulse_width_in_500ns); | 560 | unlock: |
561 | spin_unlock_irqrestore(&dev->hw_lock, flags); | ||
562 | } | ||
360 | 563 | ||
361 | ene_hw_write_reg(dev, ENE_TX_PERIOD, ENE_TX_PERIOD_UNKBIT | | 564 | /* Enable/disable transmitters */ |
362 | tx_period_in500ns); | 565 | static void ene_tx_set_transmitters(struct ene_device *dev) |
566 | { | ||
567 | unsigned long flags; | ||
363 | 568 | ||
364 | ene_hw_write_reg(dev, ENE_TX_PERIOD_PULSE, | 569 | spin_lock_irqsave(&dev->hw_lock, flags); |
365 | tx_pulse_width_in_500ns); | 570 | ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41, |
571 | !!(dev->transmitter_mask & 0x01)); | ||
572 | ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D, | ||
573 | !!(dev->transmitter_mask & 0x02)); | ||
574 | spin_unlock_irqrestore(&dev->hw_lock, flags); | ||
575 | } | ||
366 | 576 | ||
367 | conf1 |= ENE_CIR_CONF1_TX_CARR; | 577 | /* prepare transmission */ |
368 | } else | 578 | static void ene_tx_enable(struct ene_device *dev) |
369 | conf1 &= ~ENE_CIR_CONF1_TX_CARR; | 579 | { |
580 | u8 conf1 = ene_read_reg(dev, ENE_CIRCFG); | ||
581 | u8 fwreg2 = ene_read_reg(dev, ENE_FW2); | ||
582 | |||
583 | dev->saved_conf1 = conf1; | ||
584 | |||
585 | /* Show information about currently connected transmitter jacks */ | ||
586 | if (fwreg2 & ENE_FW2_EMMITER1_CONN) | ||
587 | dbg("TX: Transmitter #1 is connected"); | ||
588 | |||
589 | if (fwreg2 & ENE_FW2_EMMITER2_CONN) | ||
590 | dbg("TX: Transmitter #2 is connected"); | ||
370 | 591 | ||
371 | ene_hw_write_reg(dev, ENE_CIR_CONF1, conf1); | 592 | if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN))) |
593 | ene_warn("TX: transmitter cable isn't connected!"); | ||
372 | 594 | ||
595 | /* disable receive on revc */ | ||
596 | if (dev->hw_revision == ENE_HW_C) | ||
597 | conf1 &= ~ENE_CIRCFG_RX_EN; | ||
598 | |||
599 | /* Enable TX engine */ | ||
600 | conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ; | ||
601 | ene_write_reg(dev, ENE_CIRCFG, conf1); | ||
373 | } | 602 | } |
374 | 603 | ||
375 | /* end transmission */ | 604 | /* end transmission */ |
376 | static void ene_tx_complete(struct ene_device *dev) | 605 | static void ene_tx_disable(struct ene_device *dev) |
377 | { | 606 | { |
378 | ene_hw_write_reg(dev, ENE_CIR_CONF1, dev->saved_conf1); | 607 | ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1); |
379 | dev->tx_buffer = NULL; | 608 | dev->tx_buffer = NULL; |
380 | } | 609 | } |
381 | 610 | ||
382 | /* set transmit mask */ | ||
383 | static void ene_tx_hw_set_transmiter_mask(struct ene_device *dev) | ||
384 | { | ||
385 | u8 txport1 = ene_hw_read_reg(dev, ENE_TX_PORT1) & ~ENE_TX_PORT1_EN; | ||
386 | u8 txport2 = ene_hw_read_reg(dev, ENE_TX_PORT2) & ~ENE_TX_PORT2_EN; | ||
387 | |||
388 | if (dev->transmitter_mask & 0x01) | ||
389 | txport1 |= ENE_TX_PORT1_EN; | ||
390 | |||
391 | if (dev->transmitter_mask & 0x02) | ||
392 | txport2 |= ENE_TX_PORT2_EN; | ||
393 | |||
394 | ene_hw_write_reg(dev, ENE_TX_PORT1, txport1); | ||
395 | ene_hw_write_reg(dev, ENE_TX_PORT2, txport2); | ||
396 | } | ||
397 | 611 | ||
398 | /* TX one sample - must be called with dev->hw_lock*/ | 612 | /* TX one sample - must be called with dev->hw_lock*/ |
399 | static void ene_tx_sample(struct ene_device *dev) | 613 | static void ene_tx_sample(struct ene_device *dev) |
400 | { | 614 | { |
401 | u8 raw_tx; | 615 | u8 raw_tx; |
402 | u32 sample; | 616 | u32 sample; |
617 | bool pulse = dev->tx_sample_pulse; | ||
403 | 618 | ||
404 | if (!dev->tx_buffer) { | 619 | if (!dev->tx_buffer) { |
405 | ene_dbg("TX: attempt to transmit NULL buffer"); | 620 | ene_warn("TX: BUG: attempt to transmit NULL buffer"); |
406 | return; | 621 | return; |
407 | } | 622 | } |
408 | 623 | ||
409 | /* Grab next TX sample */ | 624 | /* Grab next TX sample */ |
410 | if (!dev->tx_sample) { | 625 | if (!dev->tx_sample) { |
411 | again: | 626 | |
412 | if (dev->tx_pos == dev->tx_len + 1) { | 627 | if (dev->tx_pos == dev->tx_len) { |
413 | if (!dev->tx_done) { | 628 | if (!dev->tx_done) { |
414 | ene_dbg("TX: no more data to send"); | 629 | dbg("TX: no more data to send"); |
415 | dev->tx_done = 1; | 630 | dev->tx_done = true; |
416 | goto exit; | 631 | goto exit; |
417 | } else { | 632 | } else { |
418 | ene_dbg("TX: last sample sent by hardware"); | 633 | dbg("TX: last sample sent by hardware"); |
419 | ene_tx_complete(dev); | 634 | ene_tx_disable(dev); |
420 | complete(&dev->tx_complete); | 635 | complete(&dev->tx_complete); |
421 | return; | 636 | return; |
422 | } | 637 | } |
@@ -425,23 +640,23 @@ again: | |||
425 | sample = dev->tx_buffer[dev->tx_pos++]; | 640 | sample = dev->tx_buffer[dev->tx_pos++]; |
426 | dev->tx_sample_pulse = !dev->tx_sample_pulse; | 641 | dev->tx_sample_pulse = !dev->tx_sample_pulse; |
427 | 642 | ||
428 | ene_dbg("TX: sample %8d (%s)", sample, dev->tx_sample_pulse ? | 643 | dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period); |
429 | "pulse" : "space"); | ||
430 | 644 | ||
431 | dev->tx_sample = DIV_ROUND_CLOSEST(sample, ENE_TX_SMPL_PERIOD); | ||
432 | |||
433 | /* guard against too short samples */ | ||
434 | if (!dev->tx_sample) | 645 | if (!dev->tx_sample) |
435 | goto again; | 646 | dev->tx_sample = 1; |
436 | } | 647 | } |
437 | 648 | ||
438 | raw_tx = min(dev->tx_sample , (unsigned int)ENE_TX_SMLP_MASK); | 649 | raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK); |
439 | dev->tx_sample -= raw_tx; | 650 | dev->tx_sample -= raw_tx; |
440 | 651 | ||
441 | if (dev->tx_sample_pulse) | 652 | dbg("TX: sample %8d (%s)", raw_tx * sample_period, |
442 | raw_tx |= ENE_TX_PULSE_MASK; | 653 | pulse ? "pulse" : "space"); |
654 | if (pulse) | ||
655 | raw_tx |= ENE_CIRRLC_OUT_PULSE; | ||
656 | |||
657 | ene_write_reg(dev, | ||
658 | dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx); | ||
443 | 659 | ||
444 | ene_hw_write_reg(dev, ENE_TX_INPUT1 + dev->tx_reg, raw_tx); | ||
445 | dev->tx_reg = !dev->tx_reg; | 660 | dev->tx_reg = !dev->tx_reg; |
446 | exit: | 661 | exit: |
447 | /* simulate TX done interrupt */ | 662 | /* simulate TX done interrupt */ |
@@ -466,76 +681,59 @@ static int ene_irq_status(struct ene_device *dev) | |||
466 | { | 681 | { |
467 | u8 irq_status; | 682 | u8 irq_status; |
468 | u8 fw_flags1, fw_flags2; | 683 | u8 fw_flags1, fw_flags2; |
469 | int cur_rx_pointer; | ||
470 | int retval = 0; | 684 | int retval = 0; |
471 | 685 | ||
472 | fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); | 686 | fw_flags2 = ene_read_reg(dev, ENE_FW2); |
473 | cur_rx_pointer = !!(fw_flags2 & ENE_FW2_BUF_HIGH); | ||
474 | 687 | ||
475 | if (dev->hw_revision < ENE_HW_C) { | 688 | if (dev->hw_revision < ENE_HW_C) { |
476 | irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS); | 689 | irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS); |
477 | 690 | ||
478 | if (!(irq_status & ENEB_IRQ_STATUS_IR)) | 691 | if (!(irq_status & ENEB_IRQ_STATUS_IR)) |
479 | return 0; | 692 | return 0; |
480 | 693 | ||
481 | ene_hw_write_reg(dev, ENEB_IRQ_STATUS, | 694 | ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR); |
482 | irq_status & ~ENEB_IRQ_STATUS_IR); | ||
483 | dev->rx_pointer = cur_rx_pointer; | ||
484 | return ENE_IRQ_RX; | 695 | return ENE_IRQ_RX; |
485 | } | 696 | } |
486 | 697 | ||
487 | irq_status = ene_hw_read_reg(dev, ENEC_IRQ); | 698 | irq_status = ene_read_reg(dev, ENE_IRQ); |
488 | 699 | if (!(irq_status & ENE_IRQ_STATUS)) | |
489 | if (!(irq_status & ENEC_IRQ_STATUS)) | ||
490 | return 0; | 700 | return 0; |
491 | 701 | ||
492 | /* original driver does that twice - a workaround ? */ | 702 | /* original driver does that twice - a workaround ? */ |
493 | ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); | 703 | ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS); |
494 | ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); | 704 | ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS); |
495 | 705 | ||
496 | /* clear unknown flag in F8F9 */ | 706 | /* check RX interrupt */ |
497 | if (fw_flags2 & ENE_FW2_IRQ_CLR) | 707 | if (fw_flags2 & ENE_FW2_RXIRQ) { |
498 | ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR); | 708 | retval |= ENE_IRQ_RX; |
709 | ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ); | ||
710 | } | ||
499 | 711 | ||
500 | /* check if this is a TX interrupt */ | 712 | /* check TX interrupt */ |
501 | fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); | 713 | fw_flags1 = ene_read_reg(dev, ENE_FW1); |
502 | if (fw_flags1 & ENE_FW1_TXIRQ) { | 714 | if (fw_flags1 & ENE_FW1_TXIRQ) { |
503 | ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); | 715 | ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); |
504 | retval |= ENE_IRQ_TX; | 716 | retval |= ENE_IRQ_TX; |
505 | } | 717 | } |
506 | 718 | ||
507 | /* Check if this is RX interrupt */ | ||
508 | if (dev->rx_pointer != cur_rx_pointer) { | ||
509 | retval |= ENE_IRQ_RX; | ||
510 | dev->rx_pointer = cur_rx_pointer; | ||
511 | |||
512 | } else if (!(retval & ENE_IRQ_TX)) { | ||
513 | ene_dbg("RX: interrupt without change in RX pointer(%d)", | ||
514 | dev->rx_pointer); | ||
515 | retval |= ENE_IRQ_RX; | ||
516 | } | ||
517 | |||
518 | if ((retval & ENE_IRQ_RX) && (retval & ENE_IRQ_TX)) | ||
519 | ene_dbg("both RX and TX interrupt at same time"); | ||
520 | |||
521 | return retval; | 719 | return retval; |
522 | } | 720 | } |
523 | 721 | ||
524 | /* interrupt handler */ | 722 | /* interrupt handler */ |
525 | static irqreturn_t ene_isr(int irq, void *data) | 723 | static irqreturn_t ene_isr(int irq, void *data) |
526 | { | 724 | { |
527 | u16 hw_value; | 725 | u16 hw_value, reg; |
528 | int i, hw_sample; | 726 | int hw_sample, irq_status; |
529 | int pulse; | 727 | bool pulse; |
530 | int irq_status; | ||
531 | unsigned long flags; | 728 | unsigned long flags; |
532 | int carrier = 0; | ||
533 | irqreturn_t retval = IRQ_NONE; | 729 | irqreturn_t retval = IRQ_NONE; |
534 | struct ene_device *dev = (struct ene_device *)data; | 730 | struct ene_device *dev = (struct ene_device *)data; |
535 | struct ir_raw_event ev; | 731 | DEFINE_IR_RAW_EVENT(ev); |
536 | |||
537 | 732 | ||
538 | spin_lock_irqsave(&dev->hw_lock, flags); | 733 | spin_lock_irqsave(&dev->hw_lock, flags); |
734 | |||
735 | dbg_verbose("ISR called"); | ||
736 | ene_rx_read_hw_pointer(dev); | ||
539 | irq_status = ene_irq_status(dev); | 737 | irq_status = ene_irq_status(dev); |
540 | 738 | ||
541 | if (!irq_status) | 739 | if (!irq_status) |
@@ -544,9 +742,9 @@ static irqreturn_t ene_isr(int irq, void *data) | |||
544 | retval = IRQ_HANDLED; | 742 | retval = IRQ_HANDLED; |
545 | 743 | ||
546 | if (irq_status & ENE_IRQ_TX) { | 744 | if (irq_status & ENE_IRQ_TX) { |
547 | 745 | dbg_verbose("TX interrupt"); | |
548 | if (!dev->hw_learning_and_tx_capable) { | 746 | if (!dev->hw_learning_and_tx_capable) { |
549 | ene_dbg("TX interrupt on unsupported device!"); | 747 | dbg("TX interrupt on unsupported device!"); |
550 | goto unlock; | 748 | goto unlock; |
551 | } | 749 | } |
552 | ene_tx_sample(dev); | 750 | ene_tx_sample(dev); |
@@ -555,48 +753,57 @@ static irqreturn_t ene_isr(int irq, void *data) | |||
555 | if (!(irq_status & ENE_IRQ_RX)) | 753 | if (!(irq_status & ENE_IRQ_RX)) |
556 | goto unlock; | 754 | goto unlock; |
557 | 755 | ||
756 | dbg_verbose("RX interrupt"); | ||
558 | 757 | ||
559 | if (dev->carrier_detect_enabled || debug) | 758 | if (dev->hw_learning_and_tx_capable) |
560 | carrier = ene_rx_sense_carrier(dev); | 759 | ene_rx_sense_carrier(dev); |
561 | #if 0 | 760 | |
562 | /* TODO */ | 761 | /* On hardware that don't support extra buffer we need to trust |
563 | if (dev->carrier_detect_enabled && carrier) | 762 | the interrupt and not track the read pointer */ |
564 | ir_raw_event_report_frequency(dev->idev, carrier); | 763 | if (!dev->hw_extra_buffer) |
565 | #endif | 764 | dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0; |
765 | |||
766 | while (1) { | ||
767 | |||
768 | reg = ene_rx_get_sample_reg(dev); | ||
769 | |||
770 | dbg_verbose("next sample to read at: %04x", reg); | ||
771 | if (!reg) | ||
772 | break; | ||
566 | 773 | ||
567 | for (i = 0; i < ENE_SAMPLES_SIZE; i++) { | 774 | hw_value = ene_read_reg(dev, reg); |
568 | hw_value = ene_hw_read_reg(dev, | ||
569 | ENE_SAMPLE_BUFFER + dev->rx_pointer * 4 + i); | ||
570 | 775 | ||
571 | if (dev->rx_fan_input_inuse) { | 776 | if (dev->rx_fan_input_inuse) { |
777 | |||
778 | int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER; | ||
779 | |||
572 | /* read high part of the sample */ | 780 | /* read high part of the sample */ |
573 | hw_value |= ene_hw_read_reg(dev, | 781 | hw_value |= ene_read_reg(dev, reg + offset) << 8; |
574 | ENE_SAMPLE_BUFFER_FAN + | 782 | pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS; |
575 | dev->rx_pointer * 4 + i) << 8; | ||
576 | pulse = hw_value & ENE_FAN_SMPL_PULS_MSK; | ||
577 | 783 | ||
578 | /* clear space bit, and other unused bits */ | 784 | /* clear space bit, and other unused bits */ |
579 | hw_value &= ENE_FAN_VALUE_MASK; | 785 | hw_value &= ENE_FW_SMPL_BUF_FAN_MSK; |
580 | hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; | 786 | hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN; |
581 | 787 | ||
582 | } else { | 788 | } else { |
583 | pulse = !(hw_value & ENE_SAMPLE_SPC_MASK); | 789 | pulse = !(hw_value & ENE_FW_SAMPLE_SPACE); |
584 | hw_value &= ENE_SAMPLE_VALUE_MASK; | 790 | hw_value &= ~ENE_FW_SAMPLE_SPACE; |
585 | hw_sample = hw_value * sample_period; | 791 | hw_sample = hw_value * sample_period; |
586 | 792 | ||
587 | if (dev->rx_period_adjust) { | 793 | if (dev->rx_period_adjust) { |
588 | hw_sample *= (100 - dev->rx_period_adjust); | 794 | hw_sample *= 100; |
589 | hw_sample /= 100; | 795 | hw_sample /= (100 + dev->rx_period_adjust); |
590 | } | 796 | } |
591 | } | 797 | } |
592 | /* no more data */ | ||
593 | if (!(hw_value)) | ||
594 | break; | ||
595 | 798 | ||
596 | ene_dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); | 799 | if (!dev->hw_extra_buffer && !hw_sample) { |
800 | dev->r_pointer = dev->w_pointer; | ||
801 | continue; | ||
802 | } | ||
597 | 803 | ||
804 | dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); | ||
598 | 805 | ||
599 | ev.duration = hw_sample * 1000; | 806 | ev.duration = MS_TO_NS(hw_sample); |
600 | ev.pulse = pulse; | 807 | ev.pulse = pulse; |
601 | ir_raw_event_store_with_filter(dev->idev, &ev); | 808 | ir_raw_event_store_with_filter(dev->idev, &ev); |
602 | } | 809 | } |
@@ -608,19 +815,26 @@ unlock: | |||
608 | } | 815 | } |
609 | 816 | ||
610 | /* Initialize default settings */ | 817 | /* Initialize default settings */ |
611 | static void ene_setup_settings(struct ene_device *dev) | 818 | static void ene_setup_default_settings(struct ene_device *dev) |
612 | { | 819 | { |
613 | dev->tx_period = 32; | 820 | dev->tx_period = 32; |
614 | dev->tx_duty_cycle = 25; /*%*/ | 821 | dev->tx_duty_cycle = 50; /*%*/ |
615 | dev->transmitter_mask = 3; | 822 | dev->transmitter_mask = 0x03; |
823 | dev->learning_mode_enabled = learning_mode_force; | ||
616 | 824 | ||
617 | /* Force learning mode if (input == 2), otherwise | 825 | /* Set reasonable default timeout */ |
618 | let user set it with LIRC_SET_REC_CARRIER */ | 826 | dev->props->timeout = MS_TO_NS(150000); |
619 | dev->learning_enabled = | 827 | } |
620 | (input == 2 && dev->hw_learning_and_tx_capable); | ||
621 | 828 | ||
622 | dev->rx_pointer = -1; | 829 | /* Upload all hardware settings at once. Used at load and resume time */ |
830 | static void ene_setup_hw_settings(struct ene_device *dev) | ||
831 | { | ||
832 | if (dev->hw_learning_and_tx_capable) { | ||
833 | ene_tx_set_carrier(dev); | ||
834 | ene_tx_set_transmitters(dev); | ||
835 | } | ||
623 | 836 | ||
837 | ene_rx_setup(dev); | ||
624 | } | 838 | } |
625 | 839 | ||
626 | /* outside interface: called on first open*/ | 840 | /* outside interface: called on first open*/ |
@@ -630,8 +844,6 @@ static int ene_open(void *data) | |||
630 | unsigned long flags; | 844 | unsigned long flags; |
631 | 845 | ||
632 | spin_lock_irqsave(&dev->hw_lock, flags); | 846 | spin_lock_irqsave(&dev->hw_lock, flags); |
633 | dev->in_use = 1; | ||
634 | ene_setup_settings(dev); | ||
635 | ene_rx_enable(dev); | 847 | ene_rx_enable(dev); |
636 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 848 | spin_unlock_irqrestore(&dev->hw_lock, flags); |
637 | return 0; | 849 | return 0; |
@@ -645,7 +857,6 @@ static void ene_close(void *data) | |||
645 | spin_lock_irqsave(&dev->hw_lock, flags); | 857 | spin_lock_irqsave(&dev->hw_lock, flags); |
646 | 858 | ||
647 | ene_rx_disable(dev); | 859 | ene_rx_disable(dev); |
648 | dev->in_use = 0; | ||
649 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 860 | spin_unlock_irqrestore(&dev->hw_lock, flags); |
650 | } | 861 | } |
651 | 862 | ||
@@ -653,19 +864,17 @@ static void ene_close(void *data) | |||
653 | static int ene_set_tx_mask(void *data, u32 tx_mask) | 864 | static int ene_set_tx_mask(void *data, u32 tx_mask) |
654 | { | 865 | { |
655 | struct ene_device *dev = (struct ene_device *)data; | 866 | struct ene_device *dev = (struct ene_device *)data; |
656 | unsigned long flags; | 867 | dbg("TX: attempt to set transmitter mask %02x", tx_mask); |
657 | ene_dbg("TX: attempt to set transmitter mask %02x", tx_mask); | ||
658 | 868 | ||
659 | /* invalid txmask */ | 869 | /* invalid txmask */ |
660 | if (!tx_mask || tx_mask & ~0x3) { | 870 | if (!tx_mask || tx_mask & ~0x03) { |
661 | ene_dbg("TX: invalid mask"); | 871 | dbg("TX: invalid mask"); |
662 | /* return count of transmitters */ | 872 | /* return count of transmitters */ |
663 | return 2; | 873 | return 2; |
664 | } | 874 | } |
665 | 875 | ||
666 | spin_lock_irqsave(&dev->hw_lock, flags); | ||
667 | dev->transmitter_mask = tx_mask; | 876 | dev->transmitter_mask = tx_mask; |
668 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 877 | ene_tx_set_transmitters(dev); |
669 | return 0; | 878 | return 0; |
670 | } | 879 | } |
671 | 880 | ||
@@ -673,66 +882,76 @@ static int ene_set_tx_mask(void *data, u32 tx_mask) | |||
673 | static int ene_set_tx_carrier(void *data, u32 carrier) | 882 | static int ene_set_tx_carrier(void *data, u32 carrier) |
674 | { | 883 | { |
675 | struct ene_device *dev = (struct ene_device *)data; | 884 | struct ene_device *dev = (struct ene_device *)data; |
676 | unsigned long flags; | 885 | u32 period = 2000000 / carrier; |
677 | u32 period = 1000000 / carrier; /* (1 / freq) (* # usec in 1 sec) */ | ||
678 | |||
679 | ene_dbg("TX: attempt to set tx carrier to %d kHz", carrier); | ||
680 | 886 | ||
681 | if (period && (period > ENE_TX_PERIOD_MAX || | 887 | dbg("TX: attempt to set tx carrier to %d kHz", carrier); |
682 | period < ENE_TX_PERIOD_MIN)) { | ||
683 | 888 | ||
684 | ene_dbg("TX: out of range %d-%d carrier, " | 889 | if (period && (period > ENE_CIRMOD_PRD_MAX || |
685 | "falling back to 32 kHz", | 890 | period < ENE_CIRMOD_PRD_MIN)) { |
686 | 1000 / ENE_TX_PERIOD_MIN, | ||
687 | 1000 / ENE_TX_PERIOD_MAX); | ||
688 | 891 | ||
689 | period = 32; /* this is just a coincidence!!! */ | 892 | dbg("TX: out of range %d-%d kHz carrier", |
893 | 2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX); | ||
894 | return -1; | ||
690 | } | 895 | } |
691 | ene_dbg("TX: set carrier to %d kHz", carrier); | ||
692 | 896 | ||
693 | spin_lock_irqsave(&dev->hw_lock, flags); | ||
694 | dev->tx_period = period; | 897 | dev->tx_period = period; |
695 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 898 | ene_tx_set_carrier(dev); |
696 | return 0; | 899 | return 0; |
697 | } | 900 | } |
698 | 901 | ||
902 | /*outside interface : set tx duty cycle */ | ||
903 | static int ene_set_tx_duty_cycle(void *data, u32 duty_cycle) | ||
904 | { | ||
905 | struct ene_device *dev = (struct ene_device *)data; | ||
906 | dbg("TX: setting duty cycle to %d%%", duty_cycle); | ||
907 | dev->tx_duty_cycle = duty_cycle; | ||
908 | ene_tx_set_carrier(dev); | ||
909 | return 0; | ||
910 | } | ||
699 | 911 | ||
700 | /* outside interface: enable learning mode */ | 912 | /* outside interface: enable learning mode */ |
701 | static int ene_set_learning_mode(void *data, int enable) | 913 | static int ene_set_learning_mode(void *data, int enable) |
702 | { | 914 | { |
703 | struct ene_device *dev = (struct ene_device *)data; | 915 | struct ene_device *dev = (struct ene_device *)data; |
704 | unsigned long flags; | 916 | unsigned long flags; |
705 | if (enable == dev->learning_enabled) | 917 | if (enable == dev->learning_mode_enabled) |
706 | return 0; | 918 | return 0; |
707 | 919 | ||
708 | spin_lock_irqsave(&dev->hw_lock, flags); | 920 | spin_lock_irqsave(&dev->hw_lock, flags); |
709 | dev->learning_enabled = enable; | 921 | dev->learning_mode_enabled = enable; |
710 | ene_rx_set_inputs(dev); | 922 | ene_rx_disable(dev); |
923 | ene_rx_setup(dev); | ||
924 | ene_rx_enable(dev); | ||
711 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 925 | spin_unlock_irqrestore(&dev->hw_lock, flags); |
712 | return 0; | 926 | return 0; |
713 | } | 927 | } |
714 | 928 | ||
715 | /* outside interface: set rec carrier */ | 929 | static int ene_set_carrier_report(void *data, int enable) |
716 | static int ene_set_rec_carrier(void *data, u32 min, u32 max) | ||
717 | { | 930 | { |
718 | struct ene_device *dev = (struct ene_device *)data; | 931 | struct ene_device *dev = (struct ene_device *)data; |
719 | ene_set_learning_mode(dev, | 932 | unsigned long flags; |
720 | max > ENE_NORMAL_RX_HI || min < ENE_NORMAL_RX_LOW); | 933 | |
934 | if (enable == dev->carrier_detect_enabled) | ||
935 | return 0; | ||
936 | |||
937 | spin_lock_irqsave(&dev->hw_lock, flags); | ||
938 | dev->carrier_detect_enabled = enable; | ||
939 | ene_rx_disable(dev); | ||
940 | ene_rx_setup(dev); | ||
941 | ene_rx_enable(dev); | ||
942 | spin_unlock_irqrestore(&dev->hw_lock, flags); | ||
721 | return 0; | 943 | return 0; |
722 | } | 944 | } |
723 | 945 | ||
724 | /* outside interface: enable or disable idle mode */ | 946 | /* outside interface: enable or disable idle mode */ |
725 | static void ene_rx_set_idle(void *data, int idle) | 947 | static void ene_set_idle(void *data, bool idle) |
726 | { | 948 | { |
727 | struct ene_device *dev = (struct ene_device *)data; | 949 | if (idle) { |
728 | ene_dbg("%sabling idle mode", idle ? "en" : "dis"); | 950 | ene_rx_reset((struct ene_device *)data); |
729 | 951 | dbg("RX: end of data"); | |
730 | ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, | 952 | } |
731 | (enable_idle && idle) ? 0 : ENE_CIR_SAMPLE_OVERFLOW, | ||
732 | ENE_CIR_SAMPLE_OVERFLOW); | ||
733 | } | 953 | } |
734 | 954 | ||
735 | |||
736 | /* outside interface: transmit */ | 955 | /* outside interface: transmit */ |
737 | static int ene_transmit(void *data, int *buf, u32 n) | 956 | static int ene_transmit(void *data, int *buf, u32 n) |
738 | { | 957 | { |
@@ -747,12 +966,11 @@ static int ene_transmit(void *data, int *buf, u32 n) | |||
747 | dev->tx_sample = 0; | 966 | dev->tx_sample = 0; |
748 | dev->tx_sample_pulse = 0; | 967 | dev->tx_sample_pulse = 0; |
749 | 968 | ||
750 | ene_dbg("TX: %d samples", dev->tx_len); | 969 | dbg("TX: %d samples", dev->tx_len); |
751 | 970 | ||
752 | spin_lock_irqsave(&dev->hw_lock, flags); | 971 | spin_lock_irqsave(&dev->hw_lock, flags); |
753 | 972 | ||
754 | ene_tx_hw_set_transmiter_mask(dev); | 973 | ene_tx_enable(dev); |
755 | ene_tx_prepare(dev); | ||
756 | 974 | ||
757 | /* Transmit first two samples */ | 975 | /* Transmit first two samples */ |
758 | ene_tx_sample(dev); | 976 | ene_tx_sample(dev); |
@@ -761,16 +979,15 @@ static int ene_transmit(void *data, int *buf, u32 n) | |||
761 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 979 | spin_unlock_irqrestore(&dev->hw_lock, flags); |
762 | 980 | ||
763 | if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) { | 981 | if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) { |
764 | ene_dbg("TX: timeout"); | 982 | dbg("TX: timeout"); |
765 | spin_lock_irqsave(&dev->hw_lock, flags); | 983 | spin_lock_irqsave(&dev->hw_lock, flags); |
766 | ene_tx_complete(dev); | 984 | ene_tx_disable(dev); |
767 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 985 | spin_unlock_irqrestore(&dev->hw_lock, flags); |
768 | } else | 986 | } else |
769 | ene_dbg("TX: done"); | 987 | dbg("TX: done"); |
770 | return n; | 988 | return n; |
771 | } | 989 | } |
772 | 990 | ||
773 | |||
774 | /* probe entry */ | 991 | /* probe entry */ |
775 | static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) | 992 | static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) |
776 | { | 993 | { |
@@ -785,121 +1002,103 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) | |||
785 | dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); | 1002 | dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); |
786 | 1003 | ||
787 | if (!input_dev || !ir_props || !dev) | 1004 | if (!input_dev || !ir_props || !dev) |
788 | goto error; | 1005 | goto error1; |
789 | 1006 | ||
790 | /* validate resources */ | 1007 | /* validate resources */ |
791 | error = -ENODEV; | 1008 | error = -ENODEV; |
792 | 1009 | ||
793 | if (!pnp_port_valid(pnp_dev, 0) || | 1010 | if (!pnp_port_valid(pnp_dev, 0) || |
794 | pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) | 1011 | pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE) |
795 | goto error; | 1012 | goto error; |
796 | 1013 | ||
797 | if (!pnp_irq_valid(pnp_dev, 0)) | 1014 | if (!pnp_irq_valid(pnp_dev, 0)) |
798 | goto error; | 1015 | goto error; |
799 | 1016 | ||
800 | dev->hw_io = pnp_port_start(pnp_dev, 0); | ||
801 | dev->irq = pnp_irq(pnp_dev, 0); | ||
802 | spin_lock_init(&dev->hw_lock); | 1017 | spin_lock_init(&dev->hw_lock); |
803 | 1018 | ||
804 | /* claim the resources */ | 1019 | /* claim the resources */ |
805 | error = -EBUSY; | 1020 | error = -EBUSY; |
806 | if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) | 1021 | dev->hw_io = pnp_port_start(pnp_dev, 0); |
1022 | if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { | ||
1023 | dev->hw_io = -1; | ||
1024 | dev->irq = -1; | ||
807 | goto error; | 1025 | goto error; |
1026 | } | ||
808 | 1027 | ||
1028 | dev->irq = pnp_irq(pnp_dev, 0); | ||
809 | if (request_irq(dev->irq, ene_isr, | 1029 | if (request_irq(dev->irq, ene_isr, |
810 | IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) | 1030 | IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) { |
1031 | dev->irq = -1; | ||
811 | goto error; | 1032 | goto error; |
1033 | } | ||
812 | 1034 | ||
813 | pnp_set_drvdata(pnp_dev, dev); | 1035 | pnp_set_drvdata(pnp_dev, dev); |
814 | dev->pnp_dev = pnp_dev; | 1036 | dev->pnp_dev = pnp_dev; |
815 | 1037 | ||
1038 | /* don't allow too short/long sample periods */ | ||
1039 | if (sample_period < 5 || sample_period > 0x7F) | ||
1040 | sample_period = ENE_DEFAULT_SAMPLE_PERIOD; | ||
1041 | |||
816 | /* detect hardware version and features */ | 1042 | /* detect hardware version and features */ |
817 | error = ene_hw_detect(dev); | 1043 | error = ene_hw_detect(dev); |
818 | if (error) | 1044 | if (error) |
819 | goto error; | 1045 | goto error; |
820 | 1046 | ||
821 | ene_setup_settings(dev); | ||
822 | |||
823 | if (!dev->hw_learning_and_tx_capable && txsim) { | 1047 | if (!dev->hw_learning_and_tx_capable && txsim) { |
824 | dev->hw_learning_and_tx_capable = 1; | 1048 | dev->hw_learning_and_tx_capable = true; |
825 | setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, | 1049 | setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, |
826 | (long unsigned int)dev); | 1050 | (long unsigned int)dev); |
827 | ene_printk(KERN_WARNING, | 1051 | ene_warn("Simulation of TX activated"); |
828 | "Simulation of TX activated\n"); | ||
829 | } | 1052 | } |
830 | 1053 | ||
1054 | if (!dev->hw_learning_and_tx_capable) | ||
1055 | learning_mode_force = false; | ||
1056 | |||
831 | ir_props->driver_type = RC_DRIVER_IR_RAW; | 1057 | ir_props->driver_type = RC_DRIVER_IR_RAW; |
832 | ir_props->allowed_protos = IR_TYPE_ALL; | 1058 | ir_props->allowed_protos = IR_TYPE_ALL; |
833 | ir_props->priv = dev; | 1059 | ir_props->priv = dev; |
834 | ir_props->open = ene_open; | 1060 | ir_props->open = ene_open; |
835 | ir_props->close = ene_close; | 1061 | ir_props->close = ene_close; |
836 | ir_props->min_timeout = ENE_MINGAP * 1000; | 1062 | ir_props->s_idle = ene_set_idle; |
837 | ir_props->max_timeout = ENE_MAXGAP * 1000; | ||
838 | ir_props->timeout = ENE_MAXGAP * 1000; | ||
839 | |||
840 | if (dev->hw_revision == ENE_HW_B) | ||
841 | ir_props->s_idle = ene_rx_set_idle; | ||
842 | |||
843 | 1063 | ||
844 | dev->props = ir_props; | 1064 | dev->props = ir_props; |
845 | dev->idev = input_dev; | 1065 | dev->idev = input_dev; |
846 | 1066 | ||
847 | /* don't allow too short/long sample periods */ | ||
848 | if (sample_period < 5 || sample_period > 0x7F) | ||
849 | sample_period = -1; | ||
850 | |||
851 | /* choose default sample period */ | ||
852 | if (sample_period == -1) { | ||
853 | |||
854 | sample_period = 50; | ||
855 | |||
856 | /* on revB, hardware idle mode eats first sample | ||
857 | if we set too low sample period */ | ||
858 | if (dev->hw_revision == ENE_HW_B && enable_idle) | ||
859 | sample_period = 75; | ||
860 | } | ||
861 | |||
862 | ir_props->rx_resolution = sample_period * 1000; | ||
863 | |||
864 | if (dev->hw_learning_and_tx_capable) { | 1067 | if (dev->hw_learning_and_tx_capable) { |
865 | |||
866 | ir_props->s_learning_mode = ene_set_learning_mode; | 1068 | ir_props->s_learning_mode = ene_set_learning_mode; |
867 | |||
868 | if (input == 0) | ||
869 | ir_props->s_rx_carrier_range = ene_set_rec_carrier; | ||
870 | |||
871 | init_completion(&dev->tx_complete); | 1069 | init_completion(&dev->tx_complete); |
872 | ir_props->tx_ir = ene_transmit; | 1070 | ir_props->tx_ir = ene_transmit; |
873 | ir_props->s_tx_mask = ene_set_tx_mask; | 1071 | ir_props->s_tx_mask = ene_set_tx_mask; |
874 | ir_props->s_tx_carrier = ene_set_tx_carrier; | 1072 | ir_props->s_tx_carrier = ene_set_tx_carrier; |
875 | ir_props->tx_resolution = ENE_TX_SMPL_PERIOD * 1000; | 1073 | ir_props->s_tx_duty_cycle = ene_set_tx_duty_cycle; |
876 | /* ir_props->s_carrier_report = ene_set_carrier_report; */ | 1074 | ir_props->s_carrier_report = ene_set_carrier_report; |
877 | } | 1075 | } |
878 | 1076 | ||
1077 | ene_rx_setup_hw_buffer(dev); | ||
1078 | ene_setup_default_settings(dev); | ||
1079 | ene_setup_hw_settings(dev); | ||
879 | 1080 | ||
880 | device_set_wakeup_capable(&pnp_dev->dev, 1); | 1081 | device_set_wakeup_capable(&pnp_dev->dev, true); |
881 | device_set_wakeup_enable(&pnp_dev->dev, 1); | 1082 | device_set_wakeup_enable(&pnp_dev->dev, true); |
882 | 1083 | ||
883 | if (dev->hw_learning_and_tx_capable) | 1084 | if (dev->hw_learning_and_tx_capable) |
884 | input_dev->name = "ENE eHome Infrared Remote Transceiver"; | 1085 | input_dev->name = "ENE eHome Infrared Remote Transceiver"; |
885 | else | 1086 | else |
886 | input_dev->name = "ENE eHome Infrared Remote Receiver"; | 1087 | input_dev->name = "ENE eHome Infrared Remote Receiver"; |
887 | 1088 | ||
888 | |||
889 | error = -ENODEV; | 1089 | error = -ENODEV; |
890 | if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props, | 1090 | if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props, |
891 | ENE_DRIVER_NAME)) | 1091 | ENE_DRIVER_NAME)) |
892 | goto error; | 1092 | goto error; |
893 | 1093 | ||
894 | 1094 | ene_notice("driver has been succesfully loaded"); | |
895 | ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); | ||
896 | return 0; | 1095 | return 0; |
897 | error: | 1096 | error: |
898 | if (dev->irq) | 1097 | if (dev && dev->irq >= 0) |
899 | free_irq(dev->irq, dev); | 1098 | free_irq(dev->irq, dev); |
900 | if (dev->hw_io) | 1099 | if (dev && dev->hw_io >= 0) |
901 | release_region(dev->hw_io, ENE_MAX_IO); | 1100 | release_region(dev->hw_io, ENE_IO_SIZE); |
902 | 1101 | error1: | |
903 | input_free_device(input_dev); | 1102 | input_free_device(input_dev); |
904 | kfree(ir_props); | 1103 | kfree(ir_props); |
905 | kfree(dev); | 1104 | kfree(dev); |
@@ -914,10 +1113,11 @@ static void ene_remove(struct pnp_dev *pnp_dev) | |||
914 | 1113 | ||
915 | spin_lock_irqsave(&dev->hw_lock, flags); | 1114 | spin_lock_irqsave(&dev->hw_lock, flags); |
916 | ene_rx_disable(dev); | 1115 | ene_rx_disable(dev); |
1116 | ene_rx_restore_hw_buffer(dev); | ||
917 | spin_unlock_irqrestore(&dev->hw_lock, flags); | 1117 | spin_unlock_irqrestore(&dev->hw_lock, flags); |
918 | 1118 | ||
919 | free_irq(dev->irq, dev); | 1119 | free_irq(dev->irq, dev); |
920 | release_region(dev->hw_io, ENE_MAX_IO); | 1120 | release_region(dev->hw_io, ENE_IO_SIZE); |
921 | ir_input_unregister(dev->idev); | 1121 | ir_input_unregister(dev->idev); |
922 | kfree(dev->props); | 1122 | kfree(dev->props); |
923 | kfree(dev); | 1123 | kfree(dev); |
@@ -927,28 +1127,29 @@ static void ene_remove(struct pnp_dev *pnp_dev) | |||
927 | static void ene_enable_wake(struct ene_device *dev, int enable) | 1127 | static void ene_enable_wake(struct ene_device *dev, int enable) |
928 | { | 1128 | { |
929 | enable = enable && device_may_wakeup(&dev->pnp_dev->dev); | 1129 | enable = enable && device_may_wakeup(&dev->pnp_dev->dev); |
930 | 1130 | dbg("wake on IR %s", enable ? "enabled" : "disabled"); | |
931 | ene_dbg("wake on IR %s", enable ? "enabled" : "disabled"); | 1131 | ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable); |
932 | |||
933 | ene_hw_write_reg_mask(dev, ENE_FW1, enable ? | ||
934 | ENE_FW1_WAKE : 0, ENE_FW1_WAKE); | ||
935 | } | 1132 | } |
936 | 1133 | ||
937 | #ifdef CONFIG_PM | 1134 | #ifdef CONFIG_PM |
938 | static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) | 1135 | static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) |
939 | { | 1136 | { |
940 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | 1137 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); |
941 | ene_enable_wake(dev, 1); | 1138 | ene_enable_wake(dev, true); |
1139 | |||
1140 | /* TODO: add support for wake pattern */ | ||
942 | return 0; | 1141 | return 0; |
943 | } | 1142 | } |
944 | 1143 | ||
945 | static int ene_resume(struct pnp_dev *pnp_dev) | 1144 | static int ene_resume(struct pnp_dev *pnp_dev) |
946 | { | 1145 | { |
947 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | 1146 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); |
948 | if (dev->in_use) | 1147 | ene_setup_hw_settings(dev); |
1148 | |||
1149 | if (dev->rx_enabled) | ||
949 | ene_rx_enable(dev); | 1150 | ene_rx_enable(dev); |
950 | 1151 | ||
951 | ene_enable_wake(dev, 0); | 1152 | ene_enable_wake(dev, false); |
952 | return 0; | 1153 | return 0; |
953 | } | 1154 | } |
954 | #endif | 1155 | #endif |
@@ -956,7 +1157,7 @@ static int ene_resume(struct pnp_dev *pnp_dev) | |||
956 | static void ene_shutdown(struct pnp_dev *pnp_dev) | 1157 | static void ene_shutdown(struct pnp_dev *pnp_dev) |
957 | { | 1158 | { |
958 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | 1159 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); |
959 | ene_enable_wake(dev, 1); | 1160 | ene_enable_wake(dev, true); |
960 | } | 1161 | } |
961 | 1162 | ||
962 | static const struct pnp_device_id ene_ids[] = { | 1163 | static const struct pnp_device_id ene_ids[] = { |
@@ -994,18 +1195,11 @@ static void ene_exit(void) | |||
994 | module_param(sample_period, int, S_IRUGO); | 1195 | module_param(sample_period, int, S_IRUGO); |
995 | MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)"); | 1196 | MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)"); |
996 | 1197 | ||
997 | module_param(enable_idle, bool, S_IRUGO | S_IWUSR); | 1198 | module_param(learning_mode_force, bool, S_IRUGO); |
998 | MODULE_PARM_DESC(enable_idle, | 1199 | MODULE_PARM_DESC(learning_mode_force, "Enable learning mode by default"); |
999 | "Enables turning off signal sampling after long inactivity time; " | ||
1000 | "if disabled might help detecting input signal (default: enabled)" | ||
1001 | " (KB3926B only)"); | ||
1002 | |||
1003 | module_param(input, bool, S_IRUGO); | ||
1004 | MODULE_PARM_DESC(input, "select which input to use " | ||
1005 | "0 - auto, 1 - standard, 2 - wideband(KB3926C+)"); | ||
1006 | 1200 | ||
1007 | module_param(debug, int, S_IRUGO | S_IWUSR); | 1201 | module_param(debug, int, S_IRUGO | S_IWUSR); |
1008 | MODULE_PARM_DESC(debug, "Enable debug (debug=2 verbose debug output)"); | 1202 | MODULE_PARM_DESC(debug, "Debug level"); |
1009 | 1203 | ||
1010 | module_param(txsim, bool, S_IRUGO); | 1204 | module_param(txsim, bool, S_IRUGO); |
1011 | MODULE_PARM_DESC(txsim, | 1205 | MODULE_PARM_DESC(txsim, |
@@ -1013,8 +1207,8 @@ MODULE_PARM_DESC(txsim, | |||
1013 | 1207 | ||
1014 | MODULE_DEVICE_TABLE(pnp, ene_ids); | 1208 | MODULE_DEVICE_TABLE(pnp, ene_ids); |
1015 | MODULE_DESCRIPTION | 1209 | MODULE_DESCRIPTION |
1016 | ("Infrared input driver for KB3926B/KB3926C/KB3926D " | 1210 | ("Infrared input driver for KB3926B/C/D/E/F " |
1017 | "(aka ENE0100/ENE0200/ENE0201) CIR port"); | 1211 | "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port"); |
1018 | 1212 | ||
1019 | MODULE_AUTHOR("Maxim Levitsky"); | 1213 | MODULE_AUTHOR("Maxim Levitsky"); |
1020 | MODULE_LICENSE("GPL"); | 1214 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/IR/ene_ir.h b/drivers/media/IR/ene_ir.h index 54c76af0d033..f5870667a433 100644 --- a/drivers/media/IR/ene_ir.h +++ b/drivers/media/IR/ene_ir.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * driver for ENE KB3926 B/C/D CIR (also known as ENE0XXX) | 2 | * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX) |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com> | 4 | * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com> |
5 | * | 5 | * |
@@ -26,43 +26,50 @@ | |||
26 | #define ENE_ADDR_HI 1 /* hi byte of register address */ | 26 | #define ENE_ADDR_HI 1 /* hi byte of register address */ |
27 | #define ENE_ADDR_LO 2 /* low byte of register address */ | 27 | #define ENE_ADDR_LO 2 /* low byte of register address */ |
28 | #define ENE_IO 3 /* read/write window */ | 28 | #define ENE_IO 3 /* read/write window */ |
29 | #define ENE_MAX_IO 4 | 29 | #define ENE_IO_SIZE 4 |
30 | 30 | ||
31 | /* 8 bytes of samples, divided in 2 halfs*/ | 31 | /* 8 bytes of samples, divided in 2 packets*/ |
32 | #define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */ | 32 | #define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */ |
33 | #define ENE_SAMPLE_SPC_MASK 0x80 /* sample is space */ | 33 | #define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */ |
34 | #define ENE_SAMPLE_VALUE_MASK 0x7F | 34 | #define ENE_FW_PACKET_SIZE 4 |
35 | #define ENE_SAMPLE_OVERFLOW 0x7F | 35 | |
36 | #define ENE_SAMPLES_SIZE 4 | 36 | /* first firmware flag register */ |
37 | 37 | #define ENE_FW1 0xF8F8 /* flagr */ | |
38 | /* fan input sample buffer */ | ||
39 | #define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */ | ||
40 | /* each sample of normal buffer */ | ||
41 | #define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */ | ||
42 | /* if set, says that sample is pulse */ | ||
43 | #define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */ | ||
44 | |||
45 | /* first firmware register */ | ||
46 | #define ENE_FW1 0xF8F8 | ||
47 | #define ENE_FW1_ENABLE 0x01 /* enable fw processing */ | 38 | #define ENE_FW1_ENABLE 0x01 /* enable fw processing */ |
48 | #define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */ | 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 */ | ||
49 | #define ENE_FW1_WAKE 0x40 /* enable wake from S3 */ | 45 | #define ENE_FW1_WAKE 0x40 /* enable wake from S3 */ |
50 | #define ENE_FW1_IRQ 0x80 /* enable interrupt */ | 46 | #define ENE_FW1_IRQ 0x80 /* enable interrupt */ |
51 | 47 | ||
52 | /* second firmware register */ | 48 | /* second firmware flag register */ |
53 | #define ENE_FW2 0xF8F9 | 49 | #define ENE_FW2 0xF8F9 /* flagw */ |
54 | #define ENE_FW2_BUF_HIGH 0x01 /* which half of the buffer to read */ | 50 | #define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */ |
55 | #define ENE_FW2_IRQ_CLR 0x04 /* clear this on IRQ */ | 51 | #define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/ |
56 | #define ENE_FW2_GP40_AS_LEARN 0x08 /* normal input is used as */ | 52 | #define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */ |
57 | /* learning input */ | 53 | #define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */ |
58 | #define ENE_FW2_FAN_AS_NRML_IN 0x40 /* fan is used as normal input */ | 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*/ | ||
59 | #define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */ | 57 | #define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */ |
60 | 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 | |||
61 | /* transmitter ports */ | 68 | /* transmitter ports */ |
62 | #define ENE_TX_PORT2 0xFC01 /* this enables one or both */ | 69 | #define ENE_GPIOFS1 0xFC01 |
63 | #define ENE_TX_PORT2_EN 0x20 /* TX ports */ | 70 | #define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */ |
64 | #define ENE_TX_PORT1 0xFC08 | 71 | #define ENE_GPIOFS8 0xFC08 |
65 | #define ENE_TX_PORT1_EN 0x02 | 72 | #define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */ |
66 | 73 | ||
67 | /* IRQ registers block (for revision B) */ | 74 | /* IRQ registers block (for revision B) */ |
68 | #define ENEB_IRQ 0xFD09 /* IRQ number */ | 75 | #define ENEB_IRQ 0xFD09 /* IRQ number */ |
@@ -70,97 +77,99 @@ | |||
70 | #define ENEB_IRQ_STATUS 0xFD80 /* irq status */ | 77 | #define ENEB_IRQ_STATUS 0xFD80 /* irq status */ |
71 | #define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */ | 78 | #define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */ |
72 | 79 | ||
73 | /* fan as input settings - only if learning capable */ | 80 | /* fan as input settings */ |
74 | #define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ | 81 | #define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */ |
75 | #define ENE_FAN_AS_IN1_EN 0xCD | 82 | #define ENE_FAN_AS_IN1_EN 0xCD |
76 | #define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ | 83 | #define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */ |
77 | #define ENE_FAN_AS_IN2_EN 0x03 | 84 | #define ENE_FAN_AS_IN2_EN 0x03 |
78 | #define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */ | ||
79 | 85 | ||
80 | /* IRQ registers block (for revision C,D) */ | 86 | /* IRQ registers block (for revision C,D) */ |
81 | #define ENEC_IRQ 0xFE9B /* new irq settings register */ | 87 | #define ENE_IRQ 0xFE9B /* new irq settings register */ |
82 | #define ENEC_IRQ_MASK 0x0F /* irq number mask */ | 88 | #define ENE_IRQ_MASK 0x0F /* irq number mask */ |
83 | #define ENEC_IRQ_UNK_EN 0x10 /* always enabled */ | 89 | #define ENE_IRQ_UNK_EN 0x10 /* always enabled */ |
84 | #define ENEC_IRQ_STATUS 0x20 /* irq status and ACK */ | 90 | #define ENE_IRQ_STATUS 0x20 /* irq status and ACK */ |
85 | 91 | ||
86 | /* CIR block settings */ | 92 | /* CIR Config register #1 */ |
87 | #define ENE_CIR_CONF1 0xFEC0 | 93 | #define ENE_CIRCFG 0xFEC0 |
88 | #define ENE_CIR_CONF1_TX_CLEAR 0x01 /* clear that on revC */ | 94 | #define ENE_CIRCFG_RX_EN 0x01 /* RX enable */ |
89 | /* while transmitting */ | 95 | #define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */ |
90 | #define ENE_CIR_CONF1_RX_ON 0x07 /* normal receiver enabled */ | 96 | #define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */ |
91 | #define ENE_CIR_CONF1_LEARN1 0x08 /* enabled on learning mode */ | 97 | #define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */ |
92 | #define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ | 98 | |
93 | #define ENE_CIR_CONF1_TX_CARR 0x80 /* send TX carrier or not */ | 99 | #define ENE_CIRCFG_TX_EN 0x10 /* TX enable */ |
94 | 100 | #define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */ | |
95 | #define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */ | 101 | #define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */ |
96 | #define ENE_CIR_CONF2_LEARN2 0x10 /* set on enable learning */ | 102 | #define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */ |
97 | #define ENE_CIR_CONF2_GPIO40DIS 0x20 /* disable input via gpio40 */ | 103 | |
98 | 104 | /* CIR config register #2 */ | |
99 | #define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */ | 105 | #define ENE_CIRCFG2 0xFEC1 |
100 | #define ENE_CIR_SAMPLE_OVERFLOW 0x80 /* interrupt on overflows if set */ | 106 | #define ENE_CIRCFG2_RLC 0x00 |
101 | 107 | #define ENE_CIRCFG2_RC5 0x01 | |
102 | 108 | #define ENE_CIRCFG2_RC6 0x02 | |
103 | /* Two byte tx buffer */ | 109 | #define ENE_CIRCFG2_NEC 0x03 |
104 | #define ENE_TX_INPUT1 0xFEC9 | 110 | #define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */ |
105 | #define ENE_TX_INPUT2 0xFECA | 111 | #define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */ |
106 | #define ENE_TX_PULSE_MASK 0x80 /* Transmitted sample is pulse */ | 112 | #define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */ |
107 | #define ENE_TX_SMLP_MASK 0x7F | 113 | #define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */ |
108 | #define ENE_TX_SMPL_PERIOD 50 /* transmit sample period - fixed */ | 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 | ||
109 | 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 */ | ||
110 | 147 | ||
111 | /* Unknown TX setting - TX sample period ??? */ | 148 | /* detected RX carrier pulse width (resolution: 500 ns) */ |
112 | #define ENE_TX_UNK1 0xFECB /* set to 0x63 */ | 149 | #define ENE_CIRCAR_HPRD 0xFECD |
113 | 150 | ||
114 | /* Current received carrier period */ | 151 | /* TX period (resolution: 500 ns, minimum 2)*/ |
115 | #define ENE_RX_CARRIER 0xFECC /* RX period (500 ns) */ | 152 | #define ENE_CIRMOD_PRD 0xFECE |
116 | #define ENE_RX_CARRIER_VALID 0x80 /* Register content valid */ | 153 | #define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/ |
117 | 154 | ||
155 | #define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */ | ||
156 | #define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */ | ||
118 | 157 | ||
119 | /* TX period (1/carrier) */ | 158 | /* TX pulse width (resolution: 500 ns)*/ |
120 | #define ENE_TX_PERIOD 0xFECE /* TX period (500 ns) */ | 159 | #define ENE_CIRMOD_HPRD 0xFECF |
121 | #define ENE_TX_PERIOD_UNKBIT 0x80 /* This bit set on transmit*/ | ||
122 | #define ENE_TX_PERIOD_PULSE 0xFECF /* TX pulse period (500 ns)*/ | ||
123 | 160 | ||
124 | /* Hardware versions */ | 161 | /* Hardware versions */ |
125 | #define ENE_HW_VERSION 0xFF00 /* hardware revision */ | 162 | #define ENE_ECHV 0xFF00 /* hardware revision */ |
126 | #define ENE_PLLFRH 0xFF16 | 163 | #define ENE_PLLFRH 0xFF16 |
127 | #define ENE_PLLFRL 0xFF17 | 164 | #define ENE_PLLFRL 0xFF17 |
165 | #define ENE_DEFAULT_PLL_FREQ 1000 | ||
128 | 166 | ||
129 | #define ENE_HW_UNK 0xFF1D | 167 | #define ENE_ECSTS 0xFF1D |
130 | #define ENE_HW_UNK_CLR 0x04 | 168 | #define ENE_ECSTS_RSRVD 0x04 |
131 | #define ENE_HW_VER_MAJOR 0xFF1E /* chip version */ | ||
132 | #define ENE_HW_VER_MINOR 0xFF1F | ||
133 | #define ENE_HW_VER_OLD 0xFD00 | ||
134 | |||
135 | /* Normal/Learning carrier ranges - only valid if we have learning input*/ | ||
136 | /* TODO: test */ | ||
137 | #define ENE_NORMAL_RX_LOW 34 | ||
138 | #define ENE_NORMAL_RX_HI 38 | ||
139 | 169 | ||
140 | /* Tx carrier range */ | 170 | #define ENE_ECVER_MAJOR 0xFF1E /* chip version */ |
141 | /* Hardware might be able to do more, but this range is enough for | 171 | #define ENE_ECVER_MINOR 0xFF1F |
142 | all purposes */ | 172 | #define ENE_HW_VER_OLD 0xFD00 |
143 | #define ENE_TX_PERIOD_MAX 32 /* corresponds to 29.4 kHz */ | ||
144 | #define ENE_TX_PERIOD_MIN 16 /* corrsponds to 62.5 kHz */ | ||
145 | |||
146 | |||
147 | |||
148 | /* Minimal and maximal gaps */ | ||
149 | |||
150 | /* Normal case: | ||
151 | Minimal gap is 0x7F * sample period | ||
152 | Maximum gap depends on hardware. | ||
153 | For KB3926B, it is unlimited, for newer models its around | ||
154 | 250000, after which HW stops sending samples, and that is | ||
155 | not possible to change */ | ||
156 | |||
157 | /* Fan case: | ||
158 | Both minimal and maximal gaps are same, and equal to 0xFFF * 0x61 | ||
159 | And there is nothing to change this setting | ||
160 | */ | ||
161 | |||
162 | #define ENE_MAXGAP 250000 | ||
163 | #define ENE_MINGAP (127 * sample_period) | ||
164 | 173 | ||
165 | /******************************************************************************/ | 174 | /******************************************************************************/ |
166 | 175 | ||
@@ -171,46 +180,60 @@ | |||
171 | 180 | ||
172 | #define ENE_HW_B 1 /* 3926B */ | 181 | #define ENE_HW_B 1 /* 3926B */ |
173 | #define ENE_HW_C 2 /* 3926C */ | 182 | #define ENE_HW_C 2 /* 3926C */ |
174 | #define ENE_HW_D 3 /* 3926D */ | 183 | #define ENE_HW_D 3 /* 3926D or later */ |
175 | 184 | ||
176 | #define ene_printk(level, text, ...) \ | 185 | #define ene_printk(level, text, ...) \ |
177 | printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__) | 186 | printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__) |
178 | 187 | ||
179 | #define ene_dbg(text, ...) \ | 188 | #define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__) |
180 | if (debug) \ | 189 | #define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__) |
181 | printk(KERN_DEBUG \ | ||
182 | ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__) | ||
183 | 190 | ||
184 | #define ene_dbg_verbose(text, ...) \ | ||
185 | if (debug > 1) \ | ||
186 | printk(KERN_DEBUG \ | ||
187 | ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__) | ||
188 | 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) | ||
189 | 205 | ||
190 | struct ene_device { | 206 | struct ene_device { |
191 | struct pnp_dev *pnp_dev; | 207 | struct pnp_dev *pnp_dev; |
192 | struct input_dev *idev; | 208 | struct input_dev *idev; |
193 | struct ir_dev_props *props; | 209 | struct ir_dev_props *props; |
194 | int in_use; | ||
195 | 210 | ||
196 | /* hw IO settings */ | 211 | /* hw IO settings */ |
197 | unsigned long hw_io; | 212 | long hw_io; |
198 | int irq; | 213 | int irq; |
199 | spinlock_t hw_lock; | 214 | spinlock_t hw_lock; |
200 | 215 | ||
201 | /* HW features */ | 216 | /* HW features */ |
202 | int hw_revision; /* hardware revision */ | 217 | int hw_revision; /* hardware revision */ |
203 | bool hw_learning_and_tx_capable; /* learning capable */ | 218 | bool hw_use_gpio_0a; /* gpio0a is demodulated input*/ |
204 | bool hw_gpio40_learning; /* gpio40 is learning */ | 219 | bool hw_extra_buffer; /* hardware has 'extra buffer' */ |
205 | bool hw_fan_as_normal_input; /* fan input is used as */ | 220 | bool hw_fan_input; /* fan input is IR data source */ |
206 | /* regular input */ | 221 | bool hw_learning_and_tx_capable; /* learning & tx capable */ |
222 | int pll_freq; | ||
223 | int buffer_len; | ||
224 | |||
225 | /* Extra RX buffer location */ | ||
226 | int extra_buf1_address; | ||
227 | int extra_buf1_len; | ||
228 | int extra_buf2_address; | ||
229 | int extra_buf2_len; | ||
230 | |||
207 | /* HW state*/ | 231 | /* HW state*/ |
208 | int rx_pointer; /* hw pointer to rx buffer */ | 232 | int r_pointer; /* pointer to next sample to read */ |
233 | int w_pointer; /* pointer to next sample hw will write */ | ||
209 | bool rx_fan_input_inuse; /* is fan input in use for rx*/ | 234 | bool rx_fan_input_inuse; /* is fan input in use for rx*/ |
210 | int tx_reg; /* current reg used for TX */ | 235 | int tx_reg; /* current reg used for TX */ |
211 | u8 saved_conf1; /* saved FEC0 reg */ | 236 | u8 saved_conf1; /* saved FEC0 reg */ |
212 | |||
213 | /* TX sample handling */ | ||
214 | unsigned int tx_sample; /* current sample for TX */ | 237 | unsigned int tx_sample; /* current sample for TX */ |
215 | bool tx_sample_pulse; /* current sample is pulse */ | 238 | bool tx_sample_pulse; /* current sample is pulse */ |
216 | 239 | ||
@@ -229,7 +252,11 @@ struct ene_device { | |||
229 | int transmitter_mask; | 252 | int transmitter_mask; |
230 | 253 | ||
231 | /* RX settings */ | 254 | /* RX settings */ |
232 | bool learning_enabled; /* learning input enabled */ | 255 | bool learning_mode_enabled; /* learning input enabled */ |
233 | bool carrier_detect_enabled; /* carrier detect enabled */ | 256 | bool carrier_detect_enabled; /* carrier detect enabled */ |
234 | int rx_period_adjust; | 257 | int rx_period_adjust; |
258 | bool rx_enabled; | ||
235 | }; | 259 | }; |
260 | |||
261 | static int ene_irq_status(struct ene_device *dev); | ||
262 | static void ene_rx_read_hw_pointer(struct ene_device *dev); | ||
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c index faed5a332c71..bc118066bc38 100644 --- a/drivers/media/IR/imon.c +++ b/drivers/media/IR/imon.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD | 2 | * imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD |
3 | * | 3 | * |
4 | * Copyright(C) 2009 Jarod Wilson <jarod@wilsonet.com> | 4 | * Copyright(C) 2010 Jarod Wilson <jarod@wilsonet.com> |
5 | * Portions based on the original lirc_imon driver, | 5 | * Portions based on the original lirc_imon driver, |
6 | * Copyright(C) 2004 Venky Raju(dev@venky.ws) | 6 | * Copyright(C) 2004 Venky Raju(dev@venky.ws) |
7 | * | 7 | * |
@@ -26,6 +26,8 @@ | |||
26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ | ||
30 | |||
29 | #include <linux/errno.h> | 31 | #include <linux/errno.h> |
30 | #include <linux/init.h> | 32 | #include <linux/init.h> |
31 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
@@ -44,7 +46,7 @@ | |||
44 | #define MOD_AUTHOR "Jarod Wilson <jarod@wilsonet.com>" | 46 | #define MOD_AUTHOR "Jarod Wilson <jarod@wilsonet.com>" |
45 | #define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" | 47 | #define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" |
46 | #define MOD_NAME "imon" | 48 | #define MOD_NAME "imon" |
47 | #define MOD_VERSION "0.9.1" | 49 | #define MOD_VERSION "0.9.2" |
48 | 50 | ||
49 | #define DISPLAY_MINOR_BASE 144 | 51 | #define DISPLAY_MINOR_BASE 144 |
50 | #define DEVICE_NAME "lcd%d" | 52 | #define DEVICE_NAME "lcd%d" |
@@ -121,21 +123,26 @@ struct imon_context { | |||
121 | u16 vendor; /* usb vendor ID */ | 123 | u16 vendor; /* usb vendor ID */ |
122 | u16 product; /* usb product ID */ | 124 | u16 product; /* usb product ID */ |
123 | 125 | ||
124 | struct input_dev *idev; /* input device for remote */ | 126 | struct input_dev *rdev; /* input device for remote */ |
127 | struct input_dev *idev; /* input device for panel & IR mouse */ | ||
125 | struct input_dev *touch; /* input device for touchscreen */ | 128 | struct input_dev *touch; /* input device for touchscreen */ |
126 | 129 | ||
130 | spinlock_t kc_lock; /* make sure we get keycodes right */ | ||
127 | u32 kc; /* current input keycode */ | 131 | u32 kc; /* current input keycode */ |
128 | u32 last_keycode; /* last reported input keycode */ | 132 | u32 last_keycode; /* last reported input keycode */ |
133 | u32 rc_scancode; /* the computed remote scancode */ | ||
134 | u8 rc_toggle; /* the computed remote toggle bit */ | ||
129 | u64 ir_type; /* iMON or MCE (RC6) IR protocol? */ | 135 | u64 ir_type; /* iMON or MCE (RC6) IR protocol? */ |
130 | u8 mce_toggle_bit; /* last mce toggle bit */ | ||
131 | bool release_code; /* some keys send a release code */ | 136 | bool release_code; /* some keys send a release code */ |
132 | 137 | ||
133 | u8 display_type; /* store the display type */ | 138 | u8 display_type; /* store the display type */ |
134 | bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */ | 139 | bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */ |
135 | 140 | ||
141 | char name_rdev[128]; /* rc input device name */ | ||
142 | char phys_rdev[64]; /* rc input device phys path */ | ||
143 | |||
136 | char name_idev[128]; /* input device name */ | 144 | char name_idev[128]; /* input device name */ |
137 | char phys_idev[64]; /* input device phys path */ | 145 | char phys_idev[64]; /* input device phys path */ |
138 | struct timer_list itimer; /* input device timer, need for rc6 */ | ||
139 | 146 | ||
140 | char name_touch[128]; /* touch screen name */ | 147 | char name_touch[128]; /* touch screen name */ |
141 | char phys_touch[64]; /* touch screen phys path */ | 148 | char phys_touch[64]; /* touch screen phys path */ |
@@ -289,6 +296,9 @@ static const struct { | |||
289 | { 0x000100000000ffeell, KEY_VOLUMEUP }, | 296 | { 0x000100000000ffeell, KEY_VOLUMEUP }, |
290 | { 0x010000000000ffeell, KEY_VOLUMEDOWN }, | 297 | { 0x010000000000ffeell, KEY_VOLUMEDOWN }, |
291 | { 0x000000000100ffeell, KEY_MUTE }, | 298 | { 0x000000000100ffeell, KEY_MUTE }, |
299 | /* 0xffdc iMON MCE VFD */ | ||
300 | { 0x00010000ffffffeell, KEY_VOLUMEUP }, | ||
301 | { 0x01000000ffffffeell, KEY_VOLUMEDOWN }, | ||
292 | /* iMON Knob values */ | 302 | /* iMON Knob values */ |
293 | { 0x000100ffffffffeell, KEY_VOLUMEUP }, | 303 | { 0x000100ffffffffeell, KEY_VOLUMEUP }, |
294 | { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, | 304 | { 0x010000ffffffffeell, KEY_VOLUMEDOWN }, |
@@ -307,7 +317,7 @@ MODULE_DEVICE_TABLE(usb, imon_usb_id_table); | |||
307 | 317 | ||
308 | static bool debug; | 318 | static bool debug; |
309 | module_param(debug, bool, S_IRUGO | S_IWUSR); | 319 | module_param(debug, bool, S_IRUGO | S_IWUSR); |
310 | MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)"); | 320 | MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); |
311 | 321 | ||
312 | /* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */ | 322 | /* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */ |
313 | static int display_type; | 323 | static int display_type; |
@@ -365,15 +375,14 @@ static int display_open(struct inode *inode, struct file *file) | |||
365 | subminor = iminor(inode); | 375 | subminor = iminor(inode); |
366 | interface = usb_find_interface(&imon_driver, subminor); | 376 | interface = usb_find_interface(&imon_driver, subminor); |
367 | if (!interface) { | 377 | if (!interface) { |
368 | err("%s: could not find interface for minor %d", | 378 | pr_err("could not find interface for minor %d\n", subminor); |
369 | __func__, subminor); | ||
370 | retval = -ENODEV; | 379 | retval = -ENODEV; |
371 | goto exit; | 380 | goto exit; |
372 | } | 381 | } |
373 | ictx = usb_get_intfdata(interface); | 382 | ictx = usb_get_intfdata(interface); |
374 | 383 | ||
375 | if (!ictx) { | 384 | if (!ictx) { |
376 | err("%s: no context found for minor %d", __func__, subminor); | 385 | pr_err("no context found for minor %d\n", subminor); |
377 | retval = -ENODEV; | 386 | retval = -ENODEV; |
378 | goto exit; | 387 | goto exit; |
379 | } | 388 | } |
@@ -381,10 +390,10 @@ static int display_open(struct inode *inode, struct file *file) | |||
381 | mutex_lock(&ictx->lock); | 390 | mutex_lock(&ictx->lock); |
382 | 391 | ||
383 | if (!ictx->display_supported) { | 392 | if (!ictx->display_supported) { |
384 | err("%s: display not supported by device", __func__); | 393 | pr_err("display not supported by device\n"); |
385 | retval = -ENODEV; | 394 | retval = -ENODEV; |
386 | } else if (ictx->display_isopen) { | 395 | } else if (ictx->display_isopen) { |
387 | err("%s: display port is already open", __func__); | 396 | pr_err("display port is already open\n"); |
388 | retval = -EBUSY; | 397 | retval = -EBUSY; |
389 | } else { | 398 | } else { |
390 | ictx->display_isopen = true; | 399 | ictx->display_isopen = true; |
@@ -411,17 +420,17 @@ static int display_close(struct inode *inode, struct file *file) | |||
411 | ictx = file->private_data; | 420 | ictx = file->private_data; |
412 | 421 | ||
413 | if (!ictx) { | 422 | if (!ictx) { |
414 | err("%s: no context for device", __func__); | 423 | pr_err("no context for device\n"); |
415 | return -ENODEV; | 424 | return -ENODEV; |
416 | } | 425 | } |
417 | 426 | ||
418 | mutex_lock(&ictx->lock); | 427 | mutex_lock(&ictx->lock); |
419 | 428 | ||
420 | if (!ictx->display_supported) { | 429 | if (!ictx->display_supported) { |
421 | err("%s: display not supported by device", __func__); | 430 | pr_err("display not supported by device\n"); |
422 | retval = -ENODEV; | 431 | retval = -ENODEV; |
423 | } else if (!ictx->display_isopen) { | 432 | } else if (!ictx->display_isopen) { |
424 | err("%s: display is not open", __func__); | 433 | pr_err("display is not open\n"); |
425 | retval = -EIO; | 434 | retval = -EIO; |
426 | } else { | 435 | } else { |
427 | ictx->display_isopen = false; | 436 | ictx->display_isopen = false; |
@@ -500,19 +509,19 @@ static int send_packet(struct imon_context *ictx) | |||
500 | if (retval) { | 509 | if (retval) { |
501 | ictx->tx.busy = false; | 510 | ictx->tx.busy = false; |
502 | smp_rmb(); /* ensure later readers know we're not busy */ | 511 | smp_rmb(); /* ensure later readers know we're not busy */ |
503 | err("%s: error submitting urb(%d)", __func__, retval); | 512 | pr_err("error submitting urb(%d)\n", retval); |
504 | } else { | 513 | } else { |
505 | /* Wait for transmission to complete (or abort) */ | 514 | /* Wait for transmission to complete (or abort) */ |
506 | mutex_unlock(&ictx->lock); | 515 | mutex_unlock(&ictx->lock); |
507 | retval = wait_for_completion_interruptible( | 516 | retval = wait_for_completion_interruptible( |
508 | &ictx->tx.finished); | 517 | &ictx->tx.finished); |
509 | if (retval) | 518 | if (retval) |
510 | err("%s: task interrupted", __func__); | 519 | pr_err("task interrupted\n"); |
511 | mutex_lock(&ictx->lock); | 520 | mutex_lock(&ictx->lock); |
512 | 521 | ||
513 | retval = ictx->tx.status; | 522 | retval = ictx->tx.status; |
514 | if (retval) | 523 | if (retval) |
515 | err("%s: packet tx failed (%d)", __func__, retval); | 524 | pr_err("packet tx failed (%d)\n", retval); |
516 | } | 525 | } |
517 | 526 | ||
518 | kfree(control_req); | 527 | kfree(control_req); |
@@ -544,12 +553,12 @@ static int send_associate_24g(struct imon_context *ictx) | |||
544 | 0x00, 0x00, 0x00, 0x20 }; | 553 | 0x00, 0x00, 0x00, 0x20 }; |
545 | 554 | ||
546 | if (!ictx) { | 555 | if (!ictx) { |
547 | err("%s: no context for device", __func__); | 556 | pr_err("no context for device\n"); |
548 | return -ENODEV; | 557 | return -ENODEV; |
549 | } | 558 | } |
550 | 559 | ||
551 | if (!ictx->dev_present_intf0) { | 560 | if (!ictx->dev_present_intf0) { |
552 | err("%s: no iMON device present", __func__); | 561 | pr_err("no iMON device present\n"); |
553 | return -ENODEV; | 562 | return -ENODEV; |
554 | } | 563 | } |
555 | 564 | ||
@@ -577,7 +586,7 @@ static int send_set_imon_clock(struct imon_context *ictx, | |||
577 | int i; | 586 | int i; |
578 | 587 | ||
579 | if (!ictx) { | 588 | if (!ictx) { |
580 | err("%s: no context for device", __func__); | 589 | pr_err("no context for device\n"); |
581 | return -ENODEV; | 590 | return -ENODEV; |
582 | } | 591 | } |
583 | 592 | ||
@@ -638,8 +647,7 @@ static int send_set_imon_clock(struct imon_context *ictx, | |||
638 | memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8); | 647 | memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8); |
639 | retval = send_packet(ictx); | 648 | retval = send_packet(ictx); |
640 | if (retval) { | 649 | if (retval) { |
641 | err("%s: send_packet failed for packet %d", | 650 | pr_err("send_packet failed for packet %d\n", i); |
642 | __func__, i); | ||
643 | break; | 651 | break; |
644 | } | 652 | } |
645 | } | 653 | } |
@@ -778,7 +786,7 @@ static struct attribute *imon_display_sysfs_entries[] = { | |||
778 | NULL | 786 | NULL |
779 | }; | 787 | }; |
780 | 788 | ||
781 | static struct attribute_group imon_display_attribute_group = { | 789 | static struct attribute_group imon_display_attr_group = { |
782 | .attrs = imon_display_sysfs_entries | 790 | .attrs = imon_display_sysfs_entries |
783 | }; | 791 | }; |
784 | 792 | ||
@@ -787,7 +795,7 @@ static struct attribute *imon_rf_sysfs_entries[] = { | |||
787 | NULL | 795 | NULL |
788 | }; | 796 | }; |
789 | 797 | ||
790 | static struct attribute_group imon_rf_attribute_group = { | 798 | static struct attribute_group imon_rf_attr_group = { |
791 | .attrs = imon_rf_sysfs_entries | 799 | .attrs = imon_rf_sysfs_entries |
792 | }; | 800 | }; |
793 | 801 | ||
@@ -815,20 +823,20 @@ static ssize_t vfd_write(struct file *file, const char *buf, | |||
815 | 823 | ||
816 | ictx = file->private_data; | 824 | ictx = file->private_data; |
817 | if (!ictx) { | 825 | if (!ictx) { |
818 | err("%s: no context for device", __func__); | 826 | pr_err("no context for device\n"); |
819 | return -ENODEV; | 827 | return -ENODEV; |
820 | } | 828 | } |
821 | 829 | ||
822 | mutex_lock(&ictx->lock); | 830 | mutex_lock(&ictx->lock); |
823 | 831 | ||
824 | if (!ictx->dev_present_intf0) { | 832 | if (!ictx->dev_present_intf0) { |
825 | err("%s: no iMON device present", __func__); | 833 | pr_err("no iMON device present\n"); |
826 | retval = -ENODEV; | 834 | retval = -ENODEV; |
827 | goto exit; | 835 | goto exit; |
828 | } | 836 | } |
829 | 837 | ||
830 | if (n_bytes <= 0 || n_bytes > 32) { | 838 | if (n_bytes <= 0 || n_bytes > 32) { |
831 | err("%s: invalid payload size", __func__); | 839 | pr_err("invalid payload size\n"); |
832 | retval = -EINVAL; | 840 | retval = -EINVAL; |
833 | goto exit; | 841 | goto exit; |
834 | } | 842 | } |
@@ -854,8 +862,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, | |||
854 | 862 | ||
855 | retval = send_packet(ictx); | 863 | retval = send_packet(ictx); |
856 | if (retval) { | 864 | if (retval) { |
857 | err("%s: send packet failed for packet #%d", | 865 | pr_err("send packet failed for packet #%d\n", seq / 2); |
858 | __func__, seq/2); | ||
859 | goto exit; | 866 | goto exit; |
860 | } else { | 867 | } else { |
861 | seq += 2; | 868 | seq += 2; |
@@ -869,8 +876,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, | |||
869 | ictx->usb_tx_buf[7] = (unsigned char) seq; | 876 | ictx->usb_tx_buf[7] = (unsigned char) seq; |
870 | retval = send_packet(ictx); | 877 | retval = send_packet(ictx); |
871 | if (retval) | 878 | if (retval) |
872 | err("%s: send packet failed for packet #%d", | 879 | pr_err("send packet failed for packet #%d\n", seq / 2); |
873 | __func__, seq / 2); | ||
874 | 880 | ||
875 | exit: | 881 | exit: |
876 | mutex_unlock(&ictx->lock); | 882 | mutex_unlock(&ictx->lock); |
@@ -899,21 +905,20 @@ static ssize_t lcd_write(struct file *file, const char *buf, | |||
899 | 905 | ||
900 | ictx = file->private_data; | 906 | ictx = file->private_data; |
901 | if (!ictx) { | 907 | if (!ictx) { |
902 | err("%s: no context for device", __func__); | 908 | pr_err("no context for device\n"); |
903 | return -ENODEV; | 909 | return -ENODEV; |
904 | } | 910 | } |
905 | 911 | ||
906 | mutex_lock(&ictx->lock); | 912 | mutex_lock(&ictx->lock); |
907 | 913 | ||
908 | if (!ictx->display_supported) { | 914 | if (!ictx->display_supported) { |
909 | err("%s: no iMON display present", __func__); | 915 | pr_err("no iMON display present\n"); |
910 | retval = -ENODEV; | 916 | retval = -ENODEV; |
911 | goto exit; | 917 | goto exit; |
912 | } | 918 | } |
913 | 919 | ||
914 | if (n_bytes != 8) { | 920 | if (n_bytes != 8) { |
915 | err("%s: invalid payload size: %d (expecting 8)", | 921 | pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes); |
916 | __func__, (int) n_bytes); | ||
917 | retval = -EINVAL; | 922 | retval = -EINVAL; |
918 | goto exit; | 923 | goto exit; |
919 | } | 924 | } |
@@ -925,7 +930,7 @@ static ssize_t lcd_write(struct file *file, const char *buf, | |||
925 | 930 | ||
926 | retval = send_packet(ictx); | 931 | retval = send_packet(ictx); |
927 | if (retval) { | 932 | if (retval) { |
928 | err("%s: send packet failed!", __func__); | 933 | pr_err("send packet failed!\n"); |
929 | goto exit; | 934 | goto exit; |
930 | } else { | 935 | } else { |
931 | dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", | 936 | dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", |
@@ -958,17 +963,6 @@ static void usb_tx_callback(struct urb *urb) | |||
958 | } | 963 | } |
959 | 964 | ||
960 | /** | 965 | /** |
961 | * mce/rc6 keypresses have no distinct release code, use timer | ||
962 | */ | ||
963 | static void imon_mce_timeout(unsigned long data) | ||
964 | { | ||
965 | struct imon_context *ictx = (struct imon_context *)data; | ||
966 | |||
967 | input_report_key(ictx->idev, ictx->last_keycode, 0); | ||
968 | input_sync(ictx->idev); | ||
969 | } | ||
970 | |||
971 | /** | ||
972 | * report touchscreen input | 966 | * report touchscreen input |
973 | */ | 967 | */ |
974 | static void imon_touch_display_timeout(unsigned long data) | 968 | static void imon_touch_display_timeout(unsigned long data) |
@@ -1008,14 +1002,11 @@ int imon_ir_change_protocol(void *priv, u64 ir_type) | |||
1008 | dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); | 1002 | dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); |
1009 | ir_proto_packet[0] = 0x01; | 1003 | ir_proto_packet[0] = 0x01; |
1010 | pad_mouse = false; | 1004 | pad_mouse = false; |
1011 | init_timer(&ictx->itimer); | ||
1012 | ictx->itimer.data = (unsigned long)ictx; | ||
1013 | ictx->itimer.function = imon_mce_timeout; | ||
1014 | break; | 1005 | break; |
1015 | case IR_TYPE_UNKNOWN: | 1006 | case IR_TYPE_UNKNOWN: |
1016 | case IR_TYPE_OTHER: | 1007 | case IR_TYPE_OTHER: |
1017 | dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); | 1008 | dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); |
1018 | if (pad_stabilize) | 1009 | if (pad_stabilize && !nomouse) |
1019 | pad_mouse = true; | 1010 | pad_mouse = true; |
1020 | else { | 1011 | else { |
1021 | dev_dbg(dev, "PAD stabilize functionality disabled\n"); | 1012 | dev_dbg(dev, "PAD stabilize functionality disabled\n"); |
@@ -1027,7 +1018,7 @@ int imon_ir_change_protocol(void *priv, u64 ir_type) | |||
1027 | default: | 1018 | default: |
1028 | dev_warn(dev, "Unsupported IR protocol specified, overriding " | 1019 | dev_warn(dev, "Unsupported IR protocol specified, overriding " |
1029 | "to iMON IR protocol\n"); | 1020 | "to iMON IR protocol\n"); |
1030 | if (pad_stabilize) | 1021 | if (pad_stabilize && !nomouse) |
1031 | pad_mouse = true; | 1022 | pad_mouse = true; |
1032 | else { | 1023 | else { |
1033 | dev_dbg(dev, "PAD stabilize functionality disabled\n"); | 1024 | dev_dbg(dev, "PAD stabilize functionality disabled\n"); |
@@ -1149,20 +1140,21 @@ static int stabilize(int a, int b, u16 timeout, u16 threshold) | |||
1149 | return result; | 1140 | return result; |
1150 | } | 1141 | } |
1151 | 1142 | ||
1152 | static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code) | 1143 | static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode) |
1153 | { | 1144 | { |
1154 | u32 scancode = be32_to_cpu(hw_code); | ||
1155 | u32 keycode; | 1145 | u32 keycode; |
1156 | u32 release; | 1146 | u32 release; |
1157 | bool is_release_code = false; | 1147 | bool is_release_code = false; |
1158 | 1148 | ||
1159 | /* Look for the initial press of a button */ | 1149 | /* Look for the initial press of a button */ |
1160 | keycode = ir_g_keycode_from_table(ictx->idev, scancode); | 1150 | keycode = ir_g_keycode_from_table(ictx->rdev, scancode); |
1151 | ictx->rc_toggle = 0x0; | ||
1152 | ictx->rc_scancode = scancode; | ||
1161 | 1153 | ||
1162 | /* Look for the release of a button */ | 1154 | /* Look for the release of a button */ |
1163 | if (keycode == KEY_RESERVED) { | 1155 | if (keycode == KEY_RESERVED) { |
1164 | release = scancode & ~0x4000; | 1156 | release = scancode & ~0x4000; |
1165 | keycode = ir_g_keycode_from_table(ictx->idev, release); | 1157 | keycode = ir_g_keycode_from_table(ictx->rdev, release); |
1166 | if (keycode != KEY_RESERVED) | 1158 | if (keycode != KEY_RESERVED) |
1167 | is_release_code = true; | 1159 | is_release_code = true; |
1168 | } | 1160 | } |
@@ -1172,9 +1164,8 @@ static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code) | |||
1172 | return keycode; | 1164 | return keycode; |
1173 | } | 1165 | } |
1174 | 1166 | ||
1175 | static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code) | 1167 | static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode) |
1176 | { | 1168 | { |
1177 | u32 scancode = be32_to_cpu(hw_code); | ||
1178 | u32 keycode; | 1169 | u32 keycode; |
1179 | 1170 | ||
1180 | #define MCE_KEY_MASK 0x7000 | 1171 | #define MCE_KEY_MASK 0x7000 |
@@ -1188,18 +1179,21 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code) | |||
1188 | * but we can't or them into all codes, as some keys are decoded in | 1179 | * but we can't or them into all codes, as some keys are decoded in |
1189 | * a different way w/o the same use of the toggle bit... | 1180 | * a different way w/o the same use of the toggle bit... |
1190 | */ | 1181 | */ |
1191 | if ((scancode >> 24) & 0x80) | 1182 | if (scancode & 0x80000000) |
1192 | scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT; | 1183 | scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT; |
1193 | 1184 | ||
1194 | keycode = ir_g_keycode_from_table(ictx->idev, scancode); | 1185 | ictx->rc_scancode = scancode; |
1186 | keycode = ir_g_keycode_from_table(ictx->rdev, scancode); | ||
1187 | |||
1188 | /* not used in mce mode, but make sure we know its false */ | ||
1189 | ictx->release_code = false; | ||
1195 | 1190 | ||
1196 | return keycode; | 1191 | return keycode; |
1197 | } | 1192 | } |
1198 | 1193 | ||
1199 | static u32 imon_panel_key_lookup(u64 hw_code) | 1194 | static u32 imon_panel_key_lookup(u64 code) |
1200 | { | 1195 | { |
1201 | int i; | 1196 | int i; |
1202 | u64 code = be64_to_cpu(hw_code); | ||
1203 | u32 keycode = KEY_RESERVED; | 1197 | u32 keycode = KEY_RESERVED; |
1204 | 1198 | ||
1205 | for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { | 1199 | for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) { |
@@ -1219,6 +1213,9 @@ static bool imon_mouse_event(struct imon_context *ictx, | |||
1219 | u8 right_shift = 1; | 1213 | u8 right_shift = 1; |
1220 | bool mouse_input = true; | 1214 | bool mouse_input = true; |
1221 | int dir = 0; | 1215 | int dir = 0; |
1216 | unsigned long flags; | ||
1217 | |||
1218 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1222 | 1219 | ||
1223 | /* newer iMON device PAD or mouse button */ | 1220 | /* newer iMON device PAD or mouse button */ |
1224 | if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { | 1221 | if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) { |
@@ -1250,6 +1247,8 @@ static bool imon_mouse_event(struct imon_context *ictx, | |||
1250 | } else | 1247 | } else |
1251 | mouse_input = false; | 1248 | mouse_input = false; |
1252 | 1249 | ||
1250 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1251 | |||
1253 | if (mouse_input) { | 1252 | if (mouse_input) { |
1254 | dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); | 1253 | dev_dbg(ictx->dev, "sending mouse data via input subsystem\n"); |
1255 | 1254 | ||
@@ -1264,7 +1263,9 @@ static bool imon_mouse_event(struct imon_context *ictx, | |||
1264 | buf[1] >> right_shift & 0x1); | 1263 | buf[1] >> right_shift & 0x1); |
1265 | } | 1264 | } |
1266 | input_sync(ictx->idev); | 1265 | input_sync(ictx->idev); |
1266 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1267 | ictx->last_keycode = ictx->kc; | 1267 | ictx->last_keycode = ictx->kc; |
1268 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1268 | } | 1269 | } |
1269 | 1270 | ||
1270 | return mouse_input; | 1271 | return mouse_input; |
@@ -1286,8 +1287,8 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) | |||
1286 | int dir = 0; | 1287 | int dir = 0; |
1287 | char rel_x = 0x00, rel_y = 0x00; | 1288 | char rel_x = 0x00, rel_y = 0x00; |
1288 | u16 timeout, threshold; | 1289 | u16 timeout, threshold; |
1289 | u64 temp_key; | 1290 | u32 scancode = KEY_RESERVED; |
1290 | u32 remote_key; | 1291 | unsigned long flags; |
1291 | 1292 | ||
1292 | /* | 1293 | /* |
1293 | * The imon directional pad functions more like a touchpad. Bytes 3 & 4 | 1294 | * The imon directional pad functions more like a touchpad. Bytes 3 & 4 |
@@ -1311,26 +1312,36 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) | |||
1311 | dir = stabilize((int)rel_x, (int)rel_y, | 1312 | dir = stabilize((int)rel_x, (int)rel_y, |
1312 | timeout, threshold); | 1313 | timeout, threshold); |
1313 | if (!dir) { | 1314 | if (!dir) { |
1315 | spin_lock_irqsave(&ictx->kc_lock, | ||
1316 | flags); | ||
1314 | ictx->kc = KEY_UNKNOWN; | 1317 | ictx->kc = KEY_UNKNOWN; |
1318 | spin_unlock_irqrestore(&ictx->kc_lock, | ||
1319 | flags); | ||
1315 | return; | 1320 | return; |
1316 | } | 1321 | } |
1317 | buf[2] = dir & 0xFF; | 1322 | buf[2] = dir & 0xFF; |
1318 | buf[3] = (dir >> 8) & 0xFF; | 1323 | buf[3] = (dir >> 8) & 0xFF; |
1319 | memcpy(&temp_key, buf, sizeof(temp_key)); | 1324 | scancode = be32_to_cpu(*((u32 *)buf)); |
1320 | remote_key = (u32) (le64_to_cpu(temp_key) | ||
1321 | & 0xffffffff); | ||
1322 | ictx->kc = imon_remote_key_lookup(ictx, | ||
1323 | remote_key); | ||
1324 | } | 1325 | } |
1325 | } else { | 1326 | } else { |
1327 | /* | ||
1328 | * Hack alert: instead of using keycodes, we have | ||
1329 | * to use hard-coded scancodes here... | ||
1330 | */ | ||
1326 | if (abs(rel_y) > abs(rel_x)) { | 1331 | if (abs(rel_y) > abs(rel_x)) { |
1327 | buf[2] = (rel_y > 0) ? 0x7F : 0x80; | 1332 | buf[2] = (rel_y > 0) ? 0x7F : 0x80; |
1328 | buf[3] = 0; | 1333 | buf[3] = 0; |
1329 | ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; | 1334 | if (rel_y > 0) |
1335 | scancode = 0x01007f00; /* KEY_DOWN */ | ||
1336 | else | ||
1337 | scancode = 0x01008000; /* KEY_UP */ | ||
1330 | } else { | 1338 | } else { |
1331 | buf[2] = 0; | 1339 | buf[2] = 0; |
1332 | buf[3] = (rel_x > 0) ? 0x7F : 0x80; | 1340 | buf[3] = (rel_x > 0) ? 0x7F : 0x80; |
1333 | ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; | 1341 | if (rel_x > 0) |
1342 | scancode = 0x0100007f; /* KEY_RIGHT */ | ||
1343 | else | ||
1344 | scancode = 0x01000080; /* KEY_LEFT */ | ||
1334 | } | 1345 | } |
1335 | } | 1346 | } |
1336 | 1347 | ||
@@ -1367,34 +1378,56 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) | |||
1367 | dir = stabilize((int)rel_x, (int)rel_y, | 1378 | dir = stabilize((int)rel_x, (int)rel_y, |
1368 | timeout, threshold); | 1379 | timeout, threshold); |
1369 | if (!dir) { | 1380 | if (!dir) { |
1381 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1370 | ictx->kc = KEY_UNKNOWN; | 1382 | ictx->kc = KEY_UNKNOWN; |
1383 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1371 | return; | 1384 | return; |
1372 | } | 1385 | } |
1373 | buf[2] = dir & 0xFF; | 1386 | buf[2] = dir & 0xFF; |
1374 | buf[3] = (dir >> 8) & 0xFF; | 1387 | buf[3] = (dir >> 8) & 0xFF; |
1375 | memcpy(&temp_key, buf, sizeof(temp_key)); | 1388 | scancode = be32_to_cpu(*((u32 *)buf)); |
1376 | remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); | ||
1377 | ictx->kc = imon_remote_key_lookup(ictx, remote_key); | ||
1378 | } else { | 1389 | } else { |
1390 | /* | ||
1391 | * Hack alert: instead of using keycodes, we have | ||
1392 | * to use hard-coded scancodes here... | ||
1393 | */ | ||
1379 | if (abs(rel_y) > abs(rel_x)) { | 1394 | if (abs(rel_y) > abs(rel_x)) { |
1380 | buf[2] = (rel_y > 0) ? 0x7F : 0x80; | 1395 | buf[2] = (rel_y > 0) ? 0x7F : 0x80; |
1381 | buf[3] = 0; | 1396 | buf[3] = 0; |
1382 | ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP; | 1397 | if (rel_y > 0) |
1398 | scancode = 0x01007f00; /* KEY_DOWN */ | ||
1399 | else | ||
1400 | scancode = 0x01008000; /* KEY_UP */ | ||
1383 | } else { | 1401 | } else { |
1384 | buf[2] = 0; | 1402 | buf[2] = 0; |
1385 | buf[3] = (rel_x > 0) ? 0x7F : 0x80; | 1403 | buf[3] = (rel_x > 0) ? 0x7F : 0x80; |
1386 | ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT; | 1404 | if (rel_x > 0) |
1405 | scancode = 0x0100007f; /* KEY_RIGHT */ | ||
1406 | else | ||
1407 | scancode = 0x01000080; /* KEY_LEFT */ | ||
1387 | } | 1408 | } |
1388 | } | 1409 | } |
1389 | } | 1410 | } |
1411 | |||
1412 | if (scancode) { | ||
1413 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1414 | ictx->kc = imon_remote_key_lookup(ictx, scancode); | ||
1415 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1416 | } | ||
1390 | } | 1417 | } |
1391 | 1418 | ||
1419 | /** | ||
1420 | * figure out if these is a press or a release. We don't actually | ||
1421 | * care about repeats, as those will be auto-generated within the IR | ||
1422 | * subsystem for repeating scancodes. | ||
1423 | */ | ||
1392 | static int imon_parse_press_type(struct imon_context *ictx, | 1424 | static int imon_parse_press_type(struct imon_context *ictx, |
1393 | unsigned char *buf, u8 ktype) | 1425 | unsigned char *buf, u8 ktype) |
1394 | { | 1426 | { |
1395 | int press_type = 0; | 1427 | int press_type = 0; |
1396 | int rep_delay = ictx->idev->rep[REP_DELAY]; | 1428 | unsigned long flags; |
1397 | int rep_period = ictx->idev->rep[REP_PERIOD]; | 1429 | |
1430 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1398 | 1431 | ||
1399 | /* key release of 0x02XXXXXX key */ | 1432 | /* key release of 0x02XXXXXX key */ |
1400 | if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00) | 1433 | if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00) |
@@ -1410,22 +1443,10 @@ static int imon_parse_press_type(struct imon_context *ictx, | |||
1410 | buf[2] == 0x81 && buf[3] == 0xb7) | 1443 | buf[2] == 0x81 && buf[3] == 0xb7) |
1411 | ictx->kc = ictx->last_keycode; | 1444 | ictx->kc = ictx->last_keycode; |
1412 | 1445 | ||
1413 | /* mce-specific button handling */ | 1446 | /* mce-specific button handling, no keyup events */ |
1414 | else if (ktype == IMON_KEY_MCE) { | 1447 | else if (ktype == IMON_KEY_MCE) { |
1415 | /* initial press */ | 1448 | ictx->rc_toggle = buf[2]; |
1416 | if (ictx->kc != ictx->last_keycode | 1449 | press_type = 1; |
1417 | || buf[2] != ictx->mce_toggle_bit) { | ||
1418 | ictx->last_keycode = ictx->kc; | ||
1419 | ictx->mce_toggle_bit = buf[2]; | ||
1420 | press_type = 1; | ||
1421 | mod_timer(&ictx->itimer, | ||
1422 | jiffies + msecs_to_jiffies(rep_delay)); | ||
1423 | /* repeat */ | ||
1424 | } else { | ||
1425 | press_type = 2; | ||
1426 | mod_timer(&ictx->itimer, | ||
1427 | jiffies + msecs_to_jiffies(rep_period)); | ||
1428 | } | ||
1429 | 1450 | ||
1430 | /* incoherent or irrelevant data */ | 1451 | /* incoherent or irrelevant data */ |
1431 | } else if (ictx->kc == KEY_RESERVED) | 1452 | } else if (ictx->kc == KEY_RESERVED) |
@@ -1439,6 +1460,8 @@ static int imon_parse_press_type(struct imon_context *ictx, | |||
1439 | else | 1460 | else |
1440 | press_type = 1; | 1461 | press_type = 1; |
1441 | 1462 | ||
1463 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1464 | |||
1442 | return press_type; | 1465 | return press_type; |
1443 | } | 1466 | } |
1444 | 1467 | ||
@@ -1451,41 +1474,45 @@ static void imon_incoming_packet(struct imon_context *ictx, | |||
1451 | int len = urb->actual_length; | 1474 | int len = urb->actual_length; |
1452 | unsigned char *buf = urb->transfer_buffer; | 1475 | unsigned char *buf = urb->transfer_buffer; |
1453 | struct device *dev = ictx->dev; | 1476 | struct device *dev = ictx->dev; |
1477 | unsigned long flags; | ||
1454 | u32 kc; | 1478 | u32 kc; |
1455 | bool norelease = false; | 1479 | bool norelease = false; |
1456 | int i; | 1480 | int i; |
1457 | u64 temp_key; | 1481 | u64 scancode; |
1458 | u64 panel_key = 0; | 1482 | struct input_dev *rdev = NULL; |
1459 | u32 remote_key = 0; | 1483 | struct ir_input_dev *irdev = NULL; |
1460 | struct input_dev *idev = NULL; | ||
1461 | int press_type = 0; | 1484 | int press_type = 0; |
1462 | int msec; | 1485 | int msec; |
1463 | struct timeval t; | 1486 | struct timeval t; |
1464 | static struct timeval prev_time = { 0, 0 }; | 1487 | static struct timeval prev_time = { 0, 0 }; |
1465 | u8 ktype = IMON_KEY_IMON; | 1488 | u8 ktype; |
1466 | 1489 | ||
1467 | idev = ictx->idev; | 1490 | rdev = ictx->rdev; |
1491 | irdev = input_get_drvdata(rdev); | ||
1468 | 1492 | ||
1469 | /* filter out junk data on the older 0xffdc imon devices */ | 1493 | /* filter out junk data on the older 0xffdc imon devices */ |
1470 | if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) | 1494 | if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff)) |
1471 | return; | 1495 | return; |
1472 | 1496 | ||
1473 | /* Figure out what key was pressed */ | 1497 | /* Figure out what key was pressed */ |
1474 | memcpy(&temp_key, buf, sizeof(temp_key)); | ||
1475 | if (len == 8 && buf[7] == 0xee) { | 1498 | if (len == 8 && buf[7] == 0xee) { |
1499 | scancode = be64_to_cpu(*((u64 *)buf)); | ||
1476 | ktype = IMON_KEY_PANEL; | 1500 | ktype = IMON_KEY_PANEL; |
1477 | panel_key = le64_to_cpu(temp_key); | 1501 | kc = imon_panel_key_lookup(scancode); |
1478 | kc = imon_panel_key_lookup(panel_key); | ||
1479 | } else { | 1502 | } else { |
1480 | remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff); | 1503 | scancode = be32_to_cpu(*((u32 *)buf)); |
1481 | if (ictx->ir_type == IR_TYPE_RC6) { | 1504 | if (ictx->ir_type == IR_TYPE_RC6) { |
1505 | ktype = IMON_KEY_IMON; | ||
1482 | if (buf[0] == 0x80) | 1506 | if (buf[0] == 0x80) |
1483 | ktype = IMON_KEY_MCE; | 1507 | ktype = IMON_KEY_MCE; |
1484 | kc = imon_mce_key_lookup(ictx, remote_key); | 1508 | kc = imon_mce_key_lookup(ictx, scancode); |
1485 | } else | 1509 | } else { |
1486 | kc = imon_remote_key_lookup(ictx, remote_key); | 1510 | ktype = IMON_KEY_IMON; |
1511 | kc = imon_remote_key_lookup(ictx, scancode); | ||
1512 | } | ||
1487 | } | 1513 | } |
1488 | 1514 | ||
1515 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1489 | /* keyboard/mouse mode toggle button */ | 1516 | /* keyboard/mouse mode toggle button */ |
1490 | if (kc == KEY_KEYBOARD && !ictx->release_code) { | 1517 | if (kc == KEY_KEYBOARD && !ictx->release_code) { |
1491 | ictx->last_keycode = kc; | 1518 | ictx->last_keycode = kc; |
@@ -1493,6 +1520,7 @@ static void imon_incoming_packet(struct imon_context *ictx, | |||
1493 | ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; | 1520 | ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1; |
1494 | dev_dbg(dev, "toggling to %s mode\n", | 1521 | dev_dbg(dev, "toggling to %s mode\n", |
1495 | ictx->pad_mouse ? "mouse" : "keyboard"); | 1522 | ictx->pad_mouse ? "mouse" : "keyboard"); |
1523 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1496 | return; | 1524 | return; |
1497 | } else { | 1525 | } else { |
1498 | ictx->pad_mouse = 0; | 1526 | ictx->pad_mouse = 0; |
@@ -1501,11 +1529,13 @@ static void imon_incoming_packet(struct imon_context *ictx, | |||
1501 | } | 1529 | } |
1502 | 1530 | ||
1503 | ictx->kc = kc; | 1531 | ictx->kc = kc; |
1532 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1504 | 1533 | ||
1505 | /* send touchscreen events through input subsystem if touchpad data */ | 1534 | /* send touchscreen events through input subsystem if touchpad data */ |
1506 | if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && | 1535 | if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && |
1507 | buf[7] == 0x86) { | 1536 | buf[7] == 0x86) { |
1508 | imon_touch_event(ictx, buf); | 1537 | imon_touch_event(ictx, buf); |
1538 | return; | ||
1509 | 1539 | ||
1510 | /* look for mouse events with pad in mouse mode */ | 1540 | /* look for mouse events with pad in mouse mode */ |
1511 | } else if (ictx->pad_mouse) { | 1541 | } else if (ictx->pad_mouse) { |
@@ -1533,36 +1563,55 @@ static void imon_incoming_packet(struct imon_context *ictx, | |||
1533 | if (press_type < 0) | 1563 | if (press_type < 0) |
1534 | goto not_input_data; | 1564 | goto not_input_data; |
1535 | 1565 | ||
1566 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1536 | if (ictx->kc == KEY_UNKNOWN) | 1567 | if (ictx->kc == KEY_UNKNOWN) |
1537 | goto unknown_key; | 1568 | goto unknown_key; |
1569 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1570 | |||
1571 | if (ktype != IMON_KEY_PANEL) { | ||
1572 | if (press_type == 0) | ||
1573 | ir_keyup(irdev); | ||
1574 | else { | ||
1575 | ir_keydown(rdev, ictx->rc_scancode, ictx->rc_toggle); | ||
1576 | spin_lock_irqsave(&ictx->kc_lock, flags); | ||
1577 | ictx->last_keycode = ictx->kc; | ||
1578 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1579 | } | ||
1580 | return; | ||
1581 | } | ||
1538 | 1582 | ||
1539 | /* KEY_MUTE repeats from MCE and knob need to be suppressed */ | 1583 | /* Only panel type events left to process now */ |
1540 | if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) | 1584 | spin_lock_irqsave(&ictx->kc_lock, flags); |
1541 | && (buf[7] == 0xee || ktype == IMON_KEY_MCE)) { | 1585 | |
1586 | /* KEY_MUTE repeats from knob need to be suppressed */ | ||
1587 | if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { | ||
1542 | do_gettimeofday(&t); | 1588 | do_gettimeofday(&t); |
1543 | msec = tv2int(&t, &prev_time); | 1589 | msec = tv2int(&t, &prev_time); |
1544 | prev_time = t; | 1590 | prev_time = t; |
1545 | if (msec < idev->rep[REP_DELAY]) | 1591 | if (msec < ictx->idev->rep[REP_DELAY]) { |
1592 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1546 | return; | 1593 | return; |
1594 | } | ||
1547 | } | 1595 | } |
1596 | kc = ictx->kc; | ||
1548 | 1597 | ||
1549 | input_report_key(idev, ictx->kc, press_type); | 1598 | spin_unlock_irqrestore(&ictx->kc_lock, flags); |
1550 | input_sync(idev); | ||
1551 | 1599 | ||
1552 | /* panel keys and some remote keys don't generate a release */ | 1600 | input_report_key(ictx->idev, kc, press_type); |
1553 | if (panel_key || norelease) { | 1601 | input_sync(ictx->idev); |
1554 | input_report_key(idev, ictx->kc, 0); | ||
1555 | input_sync(idev); | ||
1556 | } | ||
1557 | 1602 | ||
1558 | ictx->last_keycode = ictx->kc; | 1603 | /* panel keys don't generate a release */ |
1604 | input_report_key(ictx->idev, kc, 0); | ||
1605 | input_sync(ictx->idev); | ||
1606 | |||
1607 | ictx->last_keycode = kc; | ||
1559 | 1608 | ||
1560 | return; | 1609 | return; |
1561 | 1610 | ||
1562 | unknown_key: | 1611 | unknown_key: |
1612 | spin_unlock_irqrestore(&ictx->kc_lock, flags); | ||
1563 | dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, | 1613 | dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, |
1564 | (panel_key ? be64_to_cpu(panel_key) : | 1614 | (long long)scancode); |
1565 | be32_to_cpu(remote_key))); | ||
1566 | return; | 1615 | return; |
1567 | 1616 | ||
1568 | not_input_data: | 1617 | not_input_data: |
@@ -1653,31 +1702,205 @@ static void usb_rx_callback_intf1(struct urb *urb) | |||
1653 | usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); | 1702 | usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); |
1654 | } | 1703 | } |
1655 | 1704 | ||
1705 | /* | ||
1706 | * The 0x15c2:0xffdc device ID was used for umpteen different imon | ||
1707 | * devices, and all of them constantly spew interrupts, even when there | ||
1708 | * is no actual data to report. However, byte 6 of this buffer looks like | ||
1709 | * its unique across device variants, so we're trying to key off that to | ||
1710 | * figure out which display type (if any) and what IR protocol the device | ||
1711 | * actually supports. These devices have their IR protocol hard-coded into | ||
1712 | * their firmware, they can't be changed on the fly like the newer hardware. | ||
1713 | */ | ||
1714 | static void imon_get_ffdc_type(struct imon_context *ictx) | ||
1715 | { | ||
1716 | u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; | ||
1717 | u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; | ||
1718 | u64 allowed_protos = IR_TYPE_OTHER; | ||
1719 | |||
1720 | switch (ffdc_cfg_byte) { | ||
1721 | /* iMON Knob, no display, iMON IR + vol knob */ | ||
1722 | case 0x21: | ||
1723 | dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR"); | ||
1724 | ictx->display_supported = false; | ||
1725 | break; | ||
1726 | /* iMON 2.4G LT (usb stick), no display, iMON RF */ | ||
1727 | case 0x4e: | ||
1728 | dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF"); | ||
1729 | ictx->display_supported = false; | ||
1730 | ictx->rf_device = true; | ||
1731 | break; | ||
1732 | /* iMON VFD, no IR (does have vol knob tho) */ | ||
1733 | case 0x35: | ||
1734 | dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR"); | ||
1735 | detected_display_type = IMON_DISPLAY_TYPE_VFD; | ||
1736 | break; | ||
1737 | /* iMON VFD, iMON IR */ | ||
1738 | case 0x24: | ||
1739 | case 0x85: | ||
1740 | dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR"); | ||
1741 | detected_display_type = IMON_DISPLAY_TYPE_VFD; | ||
1742 | break; | ||
1743 | /* iMON VFD, MCE IR */ | ||
1744 | case 0x9e: | ||
1745 | dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); | ||
1746 | detected_display_type = IMON_DISPLAY_TYPE_VFD; | ||
1747 | allowed_protos = IR_TYPE_RC6; | ||
1748 | break; | ||
1749 | /* iMON LCD, MCE IR */ | ||
1750 | case 0x9f: | ||
1751 | dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); | ||
1752 | detected_display_type = IMON_DISPLAY_TYPE_LCD; | ||
1753 | allowed_protos = IR_TYPE_RC6; | ||
1754 | break; | ||
1755 | default: | ||
1756 | dev_info(ictx->dev, "Unknown 0xffdc device, " | ||
1757 | "defaulting to VFD and iMON IR"); | ||
1758 | detected_display_type = IMON_DISPLAY_TYPE_VFD; | ||
1759 | break; | ||
1760 | } | ||
1761 | |||
1762 | printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte); | ||
1763 | |||
1764 | ictx->display_type = detected_display_type; | ||
1765 | ictx->props->allowed_protos = allowed_protos; | ||
1766 | ictx->ir_type = allowed_protos; | ||
1767 | } | ||
1768 | |||
1769 | static void imon_set_display_type(struct imon_context *ictx) | ||
1770 | { | ||
1771 | u8 configured_display_type = IMON_DISPLAY_TYPE_VFD; | ||
1772 | |||
1773 | /* | ||
1774 | * Try to auto-detect the type of display if the user hasn't set | ||
1775 | * it by hand via the display_type modparam. Default is VFD. | ||
1776 | */ | ||
1777 | |||
1778 | if (display_type == IMON_DISPLAY_TYPE_AUTO) { | ||
1779 | switch (ictx->product) { | ||
1780 | case 0xffdc: | ||
1781 | /* set in imon_get_ffdc_type() */ | ||
1782 | configured_display_type = ictx->display_type; | ||
1783 | break; | ||
1784 | case 0x0034: | ||
1785 | case 0x0035: | ||
1786 | configured_display_type = IMON_DISPLAY_TYPE_VGA; | ||
1787 | break; | ||
1788 | case 0x0038: | ||
1789 | case 0x0039: | ||
1790 | case 0x0045: | ||
1791 | configured_display_type = IMON_DISPLAY_TYPE_LCD; | ||
1792 | break; | ||
1793 | case 0x003c: | ||
1794 | case 0x0041: | ||
1795 | case 0x0042: | ||
1796 | case 0x0043: | ||
1797 | configured_display_type = IMON_DISPLAY_TYPE_NONE; | ||
1798 | ictx->display_supported = false; | ||
1799 | break; | ||
1800 | case 0x0036: | ||
1801 | case 0x0044: | ||
1802 | default: | ||
1803 | configured_display_type = IMON_DISPLAY_TYPE_VFD; | ||
1804 | break; | ||
1805 | } | ||
1806 | } else { | ||
1807 | configured_display_type = display_type; | ||
1808 | if (display_type == IMON_DISPLAY_TYPE_NONE) | ||
1809 | ictx->display_supported = false; | ||
1810 | else | ||
1811 | ictx->display_supported = true; | ||
1812 | dev_info(ictx->dev, "%s: overriding display type to %d via " | ||
1813 | "modparam\n", __func__, display_type); | ||
1814 | } | ||
1815 | |||
1816 | ictx->display_type = configured_display_type; | ||
1817 | } | ||
1818 | |||
1819 | static struct input_dev *imon_init_rdev(struct imon_context *ictx) | ||
1820 | { | ||
1821 | struct input_dev *rdev; | ||
1822 | struct ir_dev_props *props; | ||
1823 | int ret; | ||
1824 | char *ir_codes = NULL; | ||
1825 | const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, | ||
1826 | 0x00, 0x00, 0x00, 0x88 }; | ||
1827 | |||
1828 | rdev = input_allocate_device(); | ||
1829 | props = kzalloc(sizeof(*props), GFP_KERNEL); | ||
1830 | if (!rdev || !props) { | ||
1831 | dev_err(ictx->dev, "remote control dev allocation failed\n"); | ||
1832 | goto out; | ||
1833 | } | ||
1834 | |||
1835 | snprintf(ictx->name_rdev, sizeof(ictx->name_rdev), | ||
1836 | "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); | ||
1837 | usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev, | ||
1838 | sizeof(ictx->phys_rdev)); | ||
1839 | strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev)); | ||
1840 | |||
1841 | rdev->name = ictx->name_rdev; | ||
1842 | rdev->phys = ictx->phys_rdev; | ||
1843 | usb_to_input_id(ictx->usbdev_intf0, &rdev->id); | ||
1844 | rdev->dev.parent = ictx->dev; | ||
1845 | rdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); | ||
1846 | input_set_drvdata(rdev, ictx); | ||
1847 | |||
1848 | props->priv = ictx; | ||
1849 | props->driver_type = RC_DRIVER_SCANCODE; | ||
1850 | props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6; /* iMON PAD or MCE */ | ||
1851 | props->change_protocol = imon_ir_change_protocol; | ||
1852 | ictx->props = props; | ||
1853 | |||
1854 | /* Enable front-panel buttons and/or knobs */ | ||
1855 | memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); | ||
1856 | ret = send_packet(ictx); | ||
1857 | /* Not fatal, but warn about it */ | ||
1858 | if (ret) | ||
1859 | dev_info(ictx->dev, "panel buttons/knobs setup failed\n"); | ||
1860 | |||
1861 | if (ictx->product == 0xffdc) | ||
1862 | imon_get_ffdc_type(ictx); | ||
1863 | |||
1864 | imon_set_display_type(ictx); | ||
1865 | |||
1866 | if (ictx->ir_type == IR_TYPE_RC6) | ||
1867 | ir_codes = RC_MAP_IMON_MCE; | ||
1868 | else | ||
1869 | ir_codes = RC_MAP_IMON_PAD; | ||
1870 | |||
1871 | ret = ir_input_register(rdev, ir_codes, props, MOD_NAME); | ||
1872 | if (ret < 0) { | ||
1873 | dev_err(ictx->dev, "remote input dev register failed\n"); | ||
1874 | goto out; | ||
1875 | } | ||
1876 | |||
1877 | return rdev; | ||
1878 | |||
1879 | out: | ||
1880 | kfree(props); | ||
1881 | input_free_device(rdev); | ||
1882 | return NULL; | ||
1883 | } | ||
1884 | |||
1656 | static struct input_dev *imon_init_idev(struct imon_context *ictx) | 1885 | static struct input_dev *imon_init_idev(struct imon_context *ictx) |
1657 | { | 1886 | { |
1658 | struct input_dev *idev; | 1887 | struct input_dev *idev; |
1659 | struct ir_dev_props *props; | ||
1660 | int ret, i; | 1888 | int ret, i; |
1661 | 1889 | ||
1662 | idev = input_allocate_device(); | 1890 | idev = input_allocate_device(); |
1663 | if (!idev) { | 1891 | if (!idev) { |
1664 | dev_err(ictx->dev, "remote input dev allocation failed\n"); | 1892 | dev_err(ictx->dev, "input dev allocation failed\n"); |
1665 | goto idev_alloc_failed; | 1893 | goto out; |
1666 | } | ||
1667 | |||
1668 | props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); | ||
1669 | if (!props) { | ||
1670 | dev_err(ictx->dev, "remote ir dev props allocation failed\n"); | ||
1671 | goto props_alloc_failed; | ||
1672 | } | 1894 | } |
1673 | 1895 | ||
1674 | snprintf(ictx->name_idev, sizeof(ictx->name_idev), | 1896 | snprintf(ictx->name_idev, sizeof(ictx->name_idev), |
1675 | "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product); | 1897 | "iMON Panel, Knob and Mouse(%04x:%04x)", |
1898 | ictx->vendor, ictx->product); | ||
1676 | idev->name = ictx->name_idev; | 1899 | idev->name = ictx->name_idev; |
1677 | 1900 | ||
1678 | usb_make_path(ictx->usbdev_intf0, ictx->phys_idev, | 1901 | usb_make_path(ictx->usbdev_intf0, ictx->phys_idev, |
1679 | sizeof(ictx->phys_idev)); | 1902 | sizeof(ictx->phys_idev)); |
1680 | strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev)); | 1903 | strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev)); |
1681 | idev->phys = ictx->phys_idev; | 1904 | idev->phys = ictx->phys_idev; |
1682 | 1905 | ||
1683 | idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL); | 1906 | idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL); |
@@ -1693,30 +1916,20 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx) | |||
1693 | __set_bit(kc, idev->keybit); | 1916 | __set_bit(kc, idev->keybit); |
1694 | } | 1917 | } |
1695 | 1918 | ||
1696 | props->priv = ictx; | ||
1697 | props->driver_type = RC_DRIVER_SCANCODE; | ||
1698 | /* IR_TYPE_OTHER maps to iMON PAD remote, IR_TYPE_RC6 to MCE remote */ | ||
1699 | props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6; | ||
1700 | props->change_protocol = imon_ir_change_protocol; | ||
1701 | ictx->props = props; | ||
1702 | |||
1703 | usb_to_input_id(ictx->usbdev_intf0, &idev->id); | 1919 | usb_to_input_id(ictx->usbdev_intf0, &idev->id); |
1704 | idev->dev.parent = ictx->dev; | 1920 | idev->dev.parent = ictx->dev; |
1921 | input_set_drvdata(idev, ictx); | ||
1705 | 1922 | ||
1706 | ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME); | 1923 | ret = input_register_device(idev); |
1707 | if (ret < 0) { | 1924 | if (ret < 0) { |
1708 | dev_err(ictx->dev, "remote input dev register failed\n"); | 1925 | dev_err(ictx->dev, "input dev register failed\n"); |
1709 | goto idev_register_failed; | 1926 | goto out; |
1710 | } | 1927 | } |
1711 | 1928 | ||
1712 | return idev; | 1929 | return idev; |
1713 | 1930 | ||
1714 | idev_register_failed: | 1931 | out: |
1715 | kfree(props); | ||
1716 | props_alloc_failed: | ||
1717 | input_free_device(idev); | 1932 | input_free_device(idev); |
1718 | idev_alloc_failed: | ||
1719 | |||
1720 | return NULL; | 1933 | return NULL; |
1721 | } | 1934 | } |
1722 | 1935 | ||
@@ -1738,7 +1951,7 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx) | |||
1738 | 1951 | ||
1739 | usb_make_path(ictx->usbdev_intf1, ictx->phys_touch, | 1952 | usb_make_path(ictx->usbdev_intf1, ictx->phys_touch, |
1740 | sizeof(ictx->phys_touch)); | 1953 | sizeof(ictx->phys_touch)); |
1741 | strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch)); | 1954 | strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch)); |
1742 | touch->phys = ictx->phys_touch; | 1955 | touch->phys = ictx->phys_touch; |
1743 | 1956 | ||
1744 | touch->evbit[0] = | 1957 | touch->evbit[0] = |
@@ -1850,7 +2063,7 @@ static bool imon_find_endpoints(struct imon_context *ictx, | |||
1850 | 2063 | ||
1851 | /* Input endpoint is mandatory */ | 2064 | /* Input endpoint is mandatory */ |
1852 | if (!ir_ep_found) | 2065 | if (!ir_ep_found) |
1853 | err("%s: no valid input (IR) endpoint found.", __func__); | 2066 | pr_err("no valid input (IR) endpoint found\n"); |
1854 | 2067 | ||
1855 | ictx->tx_control = tx_control; | 2068 | ictx->tx_control = tx_control; |
1856 | 2069 | ||
@@ -1888,6 +2101,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) | |||
1888 | } | 2101 | } |
1889 | 2102 | ||
1890 | mutex_init(&ictx->lock); | 2103 | mutex_init(&ictx->lock); |
2104 | spin_lock_init(&ictx->kc_lock); | ||
1891 | 2105 | ||
1892 | mutex_lock(&ictx->lock); | 2106 | mutex_lock(&ictx->lock); |
1893 | 2107 | ||
@@ -1913,6 +2127,12 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) | |||
1913 | goto idev_setup_failed; | 2127 | goto idev_setup_failed; |
1914 | } | 2128 | } |
1915 | 2129 | ||
2130 | ictx->rdev = imon_init_rdev(ictx); | ||
2131 | if (!ictx->rdev) { | ||
2132 | dev_err(dev, "%s: rc device setup failed\n", __func__); | ||
2133 | goto rdev_setup_failed; | ||
2134 | } | ||
2135 | |||
1916 | usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, | 2136 | usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0, |
1917 | usb_rcvintpipe(ictx->usbdev_intf0, | 2137 | usb_rcvintpipe(ictx->usbdev_intf0, |
1918 | ictx->rx_endpoint_intf0->bEndpointAddress), | 2138 | ictx->rx_endpoint_intf0->bEndpointAddress), |
@@ -1922,15 +2142,16 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) | |||
1922 | 2142 | ||
1923 | ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL); | 2143 | ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL); |
1924 | if (ret) { | 2144 | if (ret) { |
1925 | err("%s: usb_submit_urb failed for intf0 (%d)", | 2145 | pr_err("usb_submit_urb failed for intf0 (%d)\n", ret); |
1926 | __func__, ret); | ||
1927 | goto urb_submit_failed; | 2146 | goto urb_submit_failed; |
1928 | } | 2147 | } |
1929 | 2148 | ||
1930 | return ictx; | 2149 | return ictx; |
1931 | 2150 | ||
1932 | urb_submit_failed: | 2151 | urb_submit_failed: |
1933 | ir_input_unregister(ictx->idev); | 2152 | ir_input_unregister(ictx->rdev); |
2153 | rdev_setup_failed: | ||
2154 | input_unregister_device(ictx->idev); | ||
1934 | idev_setup_failed: | 2155 | idev_setup_failed: |
1935 | find_endpoint_failed: | 2156 | find_endpoint_failed: |
1936 | mutex_unlock(&ictx->lock); | 2157 | mutex_unlock(&ictx->lock); |
@@ -1954,7 +2175,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, | |||
1954 | 2175 | ||
1955 | rx_urb = usb_alloc_urb(0, GFP_KERNEL); | 2176 | rx_urb = usb_alloc_urb(0, GFP_KERNEL); |
1956 | if (!rx_urb) { | 2177 | if (!rx_urb) { |
1957 | err("%s: usb_alloc_urb failed for IR urb", __func__); | 2178 | pr_err("usb_alloc_urb failed for IR urb\n"); |
1958 | goto rx_urb_alloc_failed; | 2179 | goto rx_urb_alloc_failed; |
1959 | } | 2180 | } |
1960 | 2181 | ||
@@ -1992,8 +2213,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, | |||
1992 | ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL); | 2213 | ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL); |
1993 | 2214 | ||
1994 | if (ret) { | 2215 | if (ret) { |
1995 | err("%s: usb_submit_urb failed for intf1 (%d)", | 2216 | pr_err("usb_submit_urb failed for intf1 (%d)\n", ret); |
1996 | __func__, ret); | ||
1997 | goto urb_submit_failed; | 2217 | goto urb_submit_failed; |
1998 | } | 2218 | } |
1999 | 2219 | ||
@@ -2012,116 +2232,6 @@ rx_urb_alloc_failed: | |||
2012 | return NULL; | 2232 | return NULL; |
2013 | } | 2233 | } |
2014 | 2234 | ||
2015 | /* | ||
2016 | * The 0x15c2:0xffdc device ID was used for umpteen different imon | ||
2017 | * devices, and all of them constantly spew interrupts, even when there | ||
2018 | * is no actual data to report. However, byte 6 of this buffer looks like | ||
2019 | * its unique across device variants, so we're trying to key off that to | ||
2020 | * figure out which display type (if any) and what IR protocol the device | ||
2021 | * actually supports. These devices have their IR protocol hard-coded into | ||
2022 | * their firmware, they can't be changed on the fly like the newer hardware. | ||
2023 | */ | ||
2024 | static void imon_get_ffdc_type(struct imon_context *ictx) | ||
2025 | { | ||
2026 | u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; | ||
2027 | u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; | ||
2028 | u64 allowed_protos = IR_TYPE_OTHER; | ||
2029 | |||
2030 | switch (ffdc_cfg_byte) { | ||
2031 | /* iMON Knob, no display, iMON IR + vol knob */ | ||
2032 | case 0x21: | ||
2033 | dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR"); | ||
2034 | ictx->display_supported = false; | ||
2035 | break; | ||
2036 | /* iMON 2.4G LT (usb stick), no display, iMON RF */ | ||
2037 | case 0x4e: | ||
2038 | dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF"); | ||
2039 | ictx->display_supported = false; | ||
2040 | ictx->rf_device = true; | ||
2041 | break; | ||
2042 | /* iMON VFD, no IR (does have vol knob tho) */ | ||
2043 | case 0x35: | ||
2044 | dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR"); | ||
2045 | detected_display_type = IMON_DISPLAY_TYPE_VFD; | ||
2046 | break; | ||
2047 | /* iMON VFD, iMON IR */ | ||
2048 | case 0x24: | ||
2049 | case 0x85: | ||
2050 | dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR"); | ||
2051 | detected_display_type = IMON_DISPLAY_TYPE_VFD; | ||
2052 | break; | ||
2053 | /* iMON LCD, MCE IR */ | ||
2054 | case 0x9e: | ||
2055 | case 0x9f: | ||
2056 | dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); | ||
2057 | detected_display_type = IMON_DISPLAY_TYPE_LCD; | ||
2058 | allowed_protos = IR_TYPE_RC6; | ||
2059 | break; | ||
2060 | default: | ||
2061 | dev_info(ictx->dev, "Unknown 0xffdc device, " | ||
2062 | "defaulting to VFD and iMON IR"); | ||
2063 | detected_display_type = IMON_DISPLAY_TYPE_VFD; | ||
2064 | break; | ||
2065 | } | ||
2066 | |||
2067 | printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte); | ||
2068 | |||
2069 | ictx->display_type = detected_display_type; | ||
2070 | ictx->props->allowed_protos = allowed_protos; | ||
2071 | ictx->ir_type = allowed_protos; | ||
2072 | } | ||
2073 | |||
2074 | static void imon_set_display_type(struct imon_context *ictx, | ||
2075 | struct usb_interface *intf) | ||
2076 | { | ||
2077 | u8 configured_display_type = IMON_DISPLAY_TYPE_VFD; | ||
2078 | |||
2079 | /* | ||
2080 | * Try to auto-detect the type of display if the user hasn't set | ||
2081 | * it by hand via the display_type modparam. Default is VFD. | ||
2082 | */ | ||
2083 | |||
2084 | if (display_type == IMON_DISPLAY_TYPE_AUTO) { | ||
2085 | switch (ictx->product) { | ||
2086 | case 0xffdc: | ||
2087 | /* set in imon_get_ffdc_type() */ | ||
2088 | configured_display_type = ictx->display_type; | ||
2089 | break; | ||
2090 | case 0x0034: | ||
2091 | case 0x0035: | ||
2092 | configured_display_type = IMON_DISPLAY_TYPE_VGA; | ||
2093 | break; | ||
2094 | case 0x0038: | ||
2095 | case 0x0039: | ||
2096 | case 0x0045: | ||
2097 | configured_display_type = IMON_DISPLAY_TYPE_LCD; | ||
2098 | break; | ||
2099 | case 0x003c: | ||
2100 | case 0x0041: | ||
2101 | case 0x0042: | ||
2102 | case 0x0043: | ||
2103 | configured_display_type = IMON_DISPLAY_TYPE_NONE; | ||
2104 | ictx->display_supported = false; | ||
2105 | break; | ||
2106 | case 0x0036: | ||
2107 | case 0x0044: | ||
2108 | default: | ||
2109 | configured_display_type = IMON_DISPLAY_TYPE_VFD; | ||
2110 | break; | ||
2111 | } | ||
2112 | } else { | ||
2113 | configured_display_type = display_type; | ||
2114 | if (display_type == IMON_DISPLAY_TYPE_NONE) | ||
2115 | ictx->display_supported = false; | ||
2116 | else | ||
2117 | ictx->display_supported = true; | ||
2118 | dev_info(ictx->dev, "%s: overriding display type to %d via " | ||
2119 | "modparam\n", __func__, display_type); | ||
2120 | } | ||
2121 | |||
2122 | ictx->display_type = configured_display_type; | ||
2123 | } | ||
2124 | |||
2125 | static void imon_init_display(struct imon_context *ictx, | 2235 | static void imon_init_display(struct imon_context *ictx, |
2126 | struct usb_interface *intf) | 2236 | struct usb_interface *intf) |
2127 | { | 2237 | { |
@@ -2130,8 +2240,7 @@ static void imon_init_display(struct imon_context *ictx, | |||
2130 | dev_dbg(ictx->dev, "Registering iMON display with sysfs\n"); | 2240 | dev_dbg(ictx->dev, "Registering iMON display with sysfs\n"); |
2131 | 2241 | ||
2132 | /* set up sysfs entry for built-in clock */ | 2242 | /* set up sysfs entry for built-in clock */ |
2133 | ret = sysfs_create_group(&intf->dev.kobj, | 2243 | ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group); |
2134 | &imon_display_attribute_group); | ||
2135 | if (ret) | 2244 | if (ret) |
2136 | dev_err(ictx->dev, "Could not create display sysfs " | 2245 | dev_err(ictx->dev, "Could not create display sysfs " |
2137 | "entries(%d)", ret); | 2246 | "entries(%d)", ret); |
@@ -2162,8 +2271,6 @@ static int __devinit imon_probe(struct usb_interface *interface, | |||
2162 | struct imon_context *ictx = NULL; | 2271 | struct imon_context *ictx = NULL; |
2163 | struct imon_context *first_if_ctx = NULL; | 2272 | struct imon_context *first_if_ctx = NULL; |
2164 | u16 vendor, product; | 2273 | u16 vendor, product; |
2165 | const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, | ||
2166 | 0x00, 0x00, 0x00, 0x88 }; | ||
2167 | 2274 | ||
2168 | code_length = BUF_CHUNK_SIZE * 8; | 2275 | code_length = BUF_CHUNK_SIZE * 8; |
2169 | 2276 | ||
@@ -2185,7 +2292,7 @@ static int __devinit imon_probe(struct usb_interface *interface, | |||
2185 | if (ifnum == 0) { | 2292 | if (ifnum == 0) { |
2186 | ictx = imon_init_intf0(interface); | 2293 | ictx = imon_init_intf0(interface); |
2187 | if (!ictx) { | 2294 | if (!ictx) { |
2188 | err("%s: failed to initialize context!\n", __func__); | 2295 | pr_err("failed to initialize context!\n"); |
2189 | ret = -ENODEV; | 2296 | ret = -ENODEV; |
2190 | goto fail; | 2297 | goto fail; |
2191 | } | 2298 | } |
@@ -2194,7 +2301,7 @@ static int __devinit imon_probe(struct usb_interface *interface, | |||
2194 | /* this is the secondary interface on the device */ | 2301 | /* this is the secondary interface on the device */ |
2195 | ictx = imon_init_intf1(interface, first_if_ctx); | 2302 | ictx = imon_init_intf1(interface, first_if_ctx); |
2196 | if (!ictx) { | 2303 | if (!ictx) { |
2197 | err("%s: failed to attach to context!\n", __func__); | 2304 | pr_err("failed to attach to context!\n"); |
2198 | ret = -ENODEV; | 2305 | ret = -ENODEV; |
2199 | goto fail; | 2306 | goto fail; |
2200 | } | 2307 | } |
@@ -2204,39 +2311,18 @@ static int __devinit imon_probe(struct usb_interface *interface, | |||
2204 | usb_set_intfdata(interface, ictx); | 2311 | usb_set_intfdata(interface, ictx); |
2205 | 2312 | ||
2206 | if (ifnum == 0) { | 2313 | if (ifnum == 0) { |
2207 | /* Enable front-panel buttons and/or knobs */ | ||
2208 | memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet)); | ||
2209 | ret = send_packet(ictx); | ||
2210 | /* Not fatal, but warn about it */ | ||
2211 | if (ret) | ||
2212 | dev_info(dev, "failed to enable panel buttons " | ||
2213 | "and/or knobs\n"); | ||
2214 | |||
2215 | if (product == 0xffdc) | ||
2216 | imon_get_ffdc_type(ictx); | ||
2217 | |||
2218 | imon_set_display_type(ictx, interface); | ||
2219 | |||
2220 | if (product == 0xffdc && ictx->rf_device) { | 2314 | if (product == 0xffdc && ictx->rf_device) { |
2221 | sysfs_err = sysfs_create_group(&interface->dev.kobj, | 2315 | sysfs_err = sysfs_create_group(&interface->dev.kobj, |
2222 | &imon_rf_attribute_group); | 2316 | &imon_rf_attr_group); |
2223 | if (sysfs_err) | 2317 | if (sysfs_err) |
2224 | err("%s: Could not create RF sysfs entries(%d)", | 2318 | pr_err("Could not create RF sysfs entries(%d)\n", |
2225 | __func__, sysfs_err); | 2319 | sysfs_err); |
2226 | } | 2320 | } |
2227 | 2321 | ||
2228 | if (ictx->display_supported) | 2322 | if (ictx->display_supported) |
2229 | imon_init_display(ictx, interface); | 2323 | imon_init_display(ictx, interface); |
2230 | } | 2324 | } |
2231 | 2325 | ||
2232 | /* set IR protocol/remote type */ | ||
2233 | ret = imon_ir_change_protocol(ictx, ictx->ir_type); | ||
2234 | if (ret) { | ||
2235 | dev_warn(dev, "%s: failed to set IR protocol, falling back " | ||
2236 | "to standard iMON protocol mode\n", __func__); | ||
2237 | ictx->ir_type = IR_TYPE_OTHER; | ||
2238 | } | ||
2239 | |||
2240 | dev_info(dev, "iMON device (%04x:%04x, intf%d) on " | 2326 | dev_info(dev, "iMON device (%04x:%04x, intf%d) on " |
2241 | "usb<%d:%d> initialized\n", vendor, product, ifnum, | 2327 | "usb<%d:%d> initialized\n", vendor, product, ifnum, |
2242 | usbdev->bus->busnum, usbdev->devnum); | 2328 | usbdev->bus->busnum, usbdev->devnum); |
@@ -2275,10 +2361,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface) | |||
2275 | * sysfs_remove_group is safe to call even if sysfs_create_group | 2361 | * sysfs_remove_group is safe to call even if sysfs_create_group |
2276 | * hasn't been called | 2362 | * hasn't been called |
2277 | */ | 2363 | */ |
2278 | sysfs_remove_group(&interface->dev.kobj, | 2364 | sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group); |
2279 | &imon_display_attribute_group); | 2365 | sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group); |
2280 | sysfs_remove_group(&interface->dev.kobj, | ||
2281 | &imon_rf_attribute_group); | ||
2282 | 2366 | ||
2283 | usb_set_intfdata(interface, NULL); | 2367 | usb_set_intfdata(interface, NULL); |
2284 | 2368 | ||
@@ -2291,7 +2375,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface) | |||
2291 | if (ifnum == 0) { | 2375 | if (ifnum == 0) { |
2292 | ictx->dev_present_intf0 = false; | 2376 | ictx->dev_present_intf0 = false; |
2293 | usb_kill_urb(ictx->rx_urb_intf0); | 2377 | usb_kill_urb(ictx->rx_urb_intf0); |
2294 | ir_input_unregister(ictx->idev); | 2378 | input_unregister_device(ictx->idev); |
2379 | ir_input_unregister(ictx->rdev); | ||
2295 | if (ictx->display_supported) { | 2380 | if (ictx->display_supported) { |
2296 | if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) | 2381 | if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) |
2297 | usb_deregister_dev(interface, &imon_lcd_class); | 2382 | usb_deregister_dev(interface, &imon_lcd_class); |
@@ -2311,11 +2396,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface) | |||
2311 | mutex_unlock(&ictx->lock); | 2396 | mutex_unlock(&ictx->lock); |
2312 | if (!ictx->display_isopen) | 2397 | if (!ictx->display_isopen) |
2313 | free_imon_context(ictx); | 2398 | free_imon_context(ictx); |
2314 | } else { | 2399 | } else |
2315 | if (ictx->ir_type == IR_TYPE_RC6) | ||
2316 | del_timer_sync(&ictx->itimer); | ||
2317 | mutex_unlock(&ictx->lock); | 2400 | mutex_unlock(&ictx->lock); |
2318 | } | ||
2319 | 2401 | ||
2320 | mutex_unlock(&driver_lock); | 2402 | mutex_unlock(&driver_lock); |
2321 | 2403 | ||
@@ -2372,7 +2454,7 @@ static int __init imon_init(void) | |||
2372 | 2454 | ||
2373 | rc = usb_register(&imon_driver); | 2455 | rc = usb_register(&imon_driver); |
2374 | if (rc) { | 2456 | if (rc) { |
2375 | err("%s: usb register failed(%d)", __func__, rc); | 2457 | pr_err("usb register failed(%d)\n", rc); |
2376 | rc = -ENODEV; | 2458 | rc = -ENODEV; |
2377 | } | 2459 | } |
2378 | 2460 | ||
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h index a85a8c7c905a..81c936bd793f 100644 --- a/drivers/media/IR/ir-core-priv.h +++ b/drivers/media/IR/ir-core-priv.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #define _IR_RAW_EVENT | 17 | #define _IR_RAW_EVENT |
18 | 18 | ||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/spinlock.h> | ||
20 | #include <media/ir-core.h> | 21 | #include <media/ir-core.h> |
21 | 22 | ||
22 | struct ir_raw_handler { | 23 | struct ir_raw_handler { |
@@ -33,6 +34,7 @@ struct ir_raw_handler { | |||
33 | struct ir_raw_event_ctrl { | 34 | struct ir_raw_event_ctrl { |
34 | struct list_head list; /* to keep track of raw clients */ | 35 | struct list_head list; /* to keep track of raw clients */ |
35 | struct task_struct *thread; | 36 | struct task_struct *thread; |
37 | spinlock_t lock; | ||
36 | struct kfifo kfifo; /* fifo for the pulse/space durations */ | 38 | struct kfifo kfifo; /* fifo for the pulse/space durations */ |
37 | ktime_t last_event; /* when last event occurred */ | 39 | ktime_t last_event; /* when last event occurred */ |
38 | enum raw_event_type last_type; /* last event type */ | 40 | enum raw_event_type last_type; /* last event type */ |
@@ -76,10 +78,22 @@ struct ir_raw_event_ctrl { | |||
76 | bool first; | 78 | bool first; |
77 | bool toggle; | 79 | bool toggle; |
78 | } jvc; | 80 | } jvc; |
81 | struct rc5_sz_dec { | ||
82 | int state; | ||
83 | u32 bits; | ||
84 | unsigned count; | ||
85 | unsigned wanted_bits; | ||
86 | } rc5_sz; | ||
79 | struct lirc_codec { | 87 | struct lirc_codec { |
80 | struct ir_input_dev *ir_dev; | 88 | struct ir_input_dev *ir_dev; |
81 | struct lirc_driver *drv; | 89 | struct lirc_driver *drv; |
82 | int carrier_low; | 90 | int carrier_low; |
91 | |||
92 | ktime_t gap_start; | ||
93 | u64 gap_duration; | ||
94 | bool gap; | ||
95 | bool send_timeout_reports; | ||
96 | |||
83 | } lirc; | 97 | } lirc; |
84 | }; | 98 | }; |
85 | 99 | ||
@@ -107,13 +121,19 @@ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration) | |||
107 | ev->duration -= duration; | 121 | ev->duration -= duration; |
108 | } | 122 | } |
109 | 123 | ||
124 | /* Returns true if event is normal pulse/space event */ | ||
125 | static inline bool is_timing_event(struct ir_raw_event ev) | ||
126 | { | ||
127 | return !ev.carrier_report && !ev.reset; | ||
128 | } | ||
129 | |||
110 | #define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) | 130 | #define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000) |
111 | #define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") | 131 | #define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space") |
112 | #define IS_RESET(ev) (ev.duration == 0) | ||
113 | /* | 132 | /* |
114 | * Routines from ir-sysfs.c - Meant to be called only internally inside | 133 | * Routines from ir-sysfs.c - Meant to be called only internally inside |
115 | * ir-core | 134 | * ir-core |
116 | */ | 135 | */ |
136 | int ir_register_input(struct input_dev *input_dev); | ||
117 | 137 | ||
118 | int ir_register_class(struct input_dev *input_dev); | 138 | int ir_register_class(struct input_dev *input_dev); |
119 | void ir_unregister_class(struct input_dev *input_dev); | 139 | void ir_unregister_class(struct input_dev *input_dev); |
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c index 77a89c4de014..63dca6e5458b 100644 --- a/drivers/media/IR/ir-jvc-decoder.c +++ b/drivers/media/IR/ir-jvc-decoder.c | |||
@@ -50,8 +50,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev) | |||
50 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC)) | 50 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC)) |
51 | return 0; | 51 | return 0; |
52 | 52 | ||
53 | if (IS_RESET(ev)) { | 53 | if (!is_timing_event(ev)) { |
54 | data->state = STATE_INACTIVE; | 54 | if (ev.reset) |
55 | data->state = STATE_INACTIVE; | ||
55 | return 0; | 56 | return 0; |
56 | } | 57 | } |
57 | 58 | ||
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c index c06b4d50a3dc..9186b45132ed 100644 --- a/drivers/media/IR/ir-keytable.c +++ b/drivers/media/IR/ir-keytable.c | |||
@@ -435,7 +435,7 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table); | |||
435 | * This routine is used to signal that a key has been released on the | 435 | * This routine is used to signal that a key has been released on the |
436 | * remote control. It reports a keyup input event via input_report_key(). | 436 | * remote control. It reports a keyup input event via input_report_key(). |
437 | */ | 437 | */ |
438 | static void ir_keyup(struct ir_input_dev *ir) | 438 | void ir_keyup(struct ir_input_dev *ir) |
439 | { | 439 | { |
440 | if (!ir->keypressed) | 440 | if (!ir->keypressed) |
441 | return; | 441 | return; |
@@ -445,6 +445,7 @@ static void ir_keyup(struct ir_input_dev *ir) | |||
445 | input_sync(ir->input_dev); | 445 | input_sync(ir->input_dev); |
446 | ir->keypressed = false; | 446 | ir->keypressed = false; |
447 | } | 447 | } |
448 | EXPORT_SYMBOL_GPL(ir_keyup); | ||
448 | 449 | ||
449 | /** | 450 | /** |
450 | * ir_timer_keyup() - generates a keyup event after a timeout | 451 | * ir_timer_keyup() - generates a keyup event after a timeout |
@@ -640,6 +641,10 @@ int __ir_input_register(struct input_dev *input_dev, | |||
640 | goto out_event; | 641 | goto out_event; |
641 | } | 642 | } |
642 | 643 | ||
644 | rc = ir_register_input(input_dev); | ||
645 | if (rc < 0) | ||
646 | goto out_event; | ||
647 | |||
643 | IR_dprintk(1, "Registered input device on %s for %s remote%s.\n", | 648 | IR_dprintk(1, "Registered input device on %s for %s remote%s.\n", |
644 | driver_name, rc_tab->name, | 649 | driver_name, rc_tab->name, |
645 | (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ? | 650 | (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ? |
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c index 1983cd3f3994..9fc0db9d344d 100644 --- a/drivers/media/IR/ir-lirc-codec.c +++ b/drivers/media/IR/ir-lirc-codec.c | |||
@@ -32,6 +32,7 @@ | |||
32 | static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev) | 32 | static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev) |
33 | { | 33 | { |
34 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | 34 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); |
35 | struct lirc_codec *lirc = &ir_dev->raw->lirc; | ||
35 | int sample; | 36 | int sample; |
36 | 37 | ||
37 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC)) | 38 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC)) |
@@ -40,21 +41,57 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev) | |||
40 | if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf) | 41 | if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf) |
41 | return -EINVAL; | 42 | return -EINVAL; |
42 | 43 | ||
43 | if (IS_RESET(ev)) | 44 | /* Packet start */ |
45 | if (ev.reset) | ||
44 | return 0; | 46 | return 0; |
45 | 47 | ||
46 | IR_dprintk(2, "LIRC data transfer started (%uus %s)\n", | 48 | /* Carrier reports */ |
47 | TO_US(ev.duration), TO_STR(ev.pulse)); | 49 | if (ev.carrier_report) { |
50 | sample = LIRC_FREQUENCY(ev.carrier); | ||
51 | |||
52 | /* Packet end */ | ||
53 | } else if (ev.timeout) { | ||
54 | |||
55 | if (lirc->gap) | ||
56 | return 0; | ||
57 | |||
58 | lirc->gap_start = ktime_get(); | ||
59 | lirc->gap = true; | ||
60 | lirc->gap_duration = ev.duration; | ||
61 | |||
62 | if (!lirc->send_timeout_reports) | ||
63 | return 0; | ||
64 | |||
65 | sample = LIRC_TIMEOUT(ev.duration / 1000); | ||
48 | 66 | ||
49 | sample = ev.duration / 1000; | 67 | /* Normal sample */ |
50 | if (ev.pulse) | 68 | } else { |
51 | sample |= PULSE_BIT; | 69 | |
70 | if (lirc->gap) { | ||
71 | int gap_sample; | ||
72 | |||
73 | lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(), | ||
74 | lirc->gap_start)); | ||
75 | |||
76 | /* Convert to ms and cap by LIRC_VALUE_MASK */ | ||
77 | do_div(lirc->gap_duration, 1000); | ||
78 | lirc->gap_duration = min(lirc->gap_duration, | ||
79 | (u64)LIRC_VALUE_MASK); | ||
80 | |||
81 | gap_sample = LIRC_SPACE(lirc->gap_duration); | ||
82 | lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, | ||
83 | (unsigned char *) &gap_sample); | ||
84 | lirc->gap = false; | ||
85 | } | ||
86 | |||
87 | sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) : | ||
88 | LIRC_SPACE(ev.duration / 1000); | ||
89 | } | ||
52 | 90 | ||
53 | lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, | 91 | lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf, |
54 | (unsigned char *) &sample); | 92 | (unsigned char *) &sample); |
55 | wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll); | 93 | wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll); |
56 | 94 | ||
57 | |||
58 | return 0; | 95 | return 0; |
59 | } | 96 | } |
60 | 97 | ||
@@ -102,7 +139,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
102 | struct ir_input_dev *ir_dev; | 139 | struct ir_input_dev *ir_dev; |
103 | int ret = 0; | 140 | int ret = 0; |
104 | void *drv_data; | 141 | void *drv_data; |
105 | unsigned long val = 0; | 142 | __u32 val = 0, tmp; |
106 | 143 | ||
107 | lirc = lirc_get_pdata(filep); | 144 | lirc = lirc_get_pdata(filep); |
108 | if (!lirc) | 145 | if (!lirc) |
@@ -115,7 +152,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
115 | drv_data = ir_dev->props->priv; | 152 | drv_data = ir_dev->props->priv; |
116 | 153 | ||
117 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | 154 | if (_IOC_DIR(cmd) & _IOC_WRITE) { |
118 | ret = get_user(val, (unsigned long *)arg); | 155 | ret = get_user(val, (__u32 *)arg); |
119 | if (ret) | 156 | if (ret) |
120 | return ret; | 157 | return ret; |
121 | } | 158 | } |
@@ -130,22 +167,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
130 | case LIRC_SET_SEND_MODE: | 167 | case LIRC_SET_SEND_MODE: |
131 | if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) | 168 | if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK)) |
132 | return -EINVAL; | 169 | return -EINVAL; |
133 | break; | 170 | return 0; |
134 | 171 | ||
135 | /* TX settings */ | 172 | /* TX settings */ |
136 | case LIRC_SET_TRANSMITTER_MASK: | 173 | case LIRC_SET_TRANSMITTER_MASK: |
137 | if (ir_dev->props->s_tx_mask) | 174 | if (!ir_dev->props->s_tx_mask) |
138 | ret = ir_dev->props->s_tx_mask(drv_data, (u32)val); | ||
139 | else | ||
140 | return -EINVAL; | 175 | return -EINVAL; |
141 | break; | 176 | |
177 | return ir_dev->props->s_tx_mask(drv_data, val); | ||
142 | 178 | ||
143 | case LIRC_SET_SEND_CARRIER: | 179 | case LIRC_SET_SEND_CARRIER: |
144 | if (ir_dev->props->s_tx_carrier) | 180 | if (!ir_dev->props->s_tx_carrier) |
145 | ir_dev->props->s_tx_carrier(drv_data, (u32)val); | ||
146 | else | ||
147 | return -EINVAL; | 181 | return -EINVAL; |
148 | break; | 182 | |
183 | return ir_dev->props->s_tx_carrier(drv_data, val); | ||
149 | 184 | ||
150 | case LIRC_SET_SEND_DUTY_CYCLE: | 185 | case LIRC_SET_SEND_DUTY_CYCLE: |
151 | if (!ir_dev->props->s_tx_duty_cycle) | 186 | if (!ir_dev->props->s_tx_duty_cycle) |
@@ -154,39 +189,42 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
154 | if (val <= 0 || val >= 100) | 189 | if (val <= 0 || val >= 100) |
155 | return -EINVAL; | 190 | return -EINVAL; |
156 | 191 | ||
157 | ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val); | 192 | return ir_dev->props->s_tx_duty_cycle(drv_data, val); |
158 | break; | ||
159 | 193 | ||
160 | /* RX settings */ | 194 | /* RX settings */ |
161 | case LIRC_SET_REC_CARRIER: | 195 | case LIRC_SET_REC_CARRIER: |
162 | if (ir_dev->props->s_rx_carrier_range) | 196 | if (!ir_dev->props->s_rx_carrier_range) |
163 | ret = ir_dev->props->s_rx_carrier_range( | ||
164 | ir_dev->props->priv, | ||
165 | ir_dev->raw->lirc.carrier_low, val); | ||
166 | else | ||
167 | return -ENOSYS; | 197 | return -ENOSYS; |
168 | 198 | ||
169 | if (!ret) | 199 | if (val <= 0) |
170 | ir_dev->raw->lirc.carrier_low = 0; | 200 | return -EINVAL; |
171 | break; | 201 | |
202 | return ir_dev->props->s_rx_carrier_range(drv_data, | ||
203 | ir_dev->raw->lirc.carrier_low, val); | ||
172 | 204 | ||
173 | case LIRC_SET_REC_CARRIER_RANGE: | 205 | case LIRC_SET_REC_CARRIER_RANGE: |
174 | if (val >= 0) | 206 | if (val <= 0) |
175 | ir_dev->raw->lirc.carrier_low = val; | 207 | return -EINVAL; |
176 | break; | ||
177 | 208 | ||
209 | ir_dev->raw->lirc.carrier_low = val; | ||
210 | return 0; | ||
178 | 211 | ||
179 | case LIRC_GET_REC_RESOLUTION: | 212 | case LIRC_GET_REC_RESOLUTION: |
180 | val = ir_dev->props->rx_resolution; | 213 | val = ir_dev->props->rx_resolution; |
181 | break; | 214 | break; |
182 | 215 | ||
183 | case LIRC_SET_WIDEBAND_RECEIVER: | 216 | case LIRC_SET_WIDEBAND_RECEIVER: |
184 | if (ir_dev->props->s_learning_mode) | 217 | if (!ir_dev->props->s_learning_mode) |
185 | return ir_dev->props->s_learning_mode( | ||
186 | ir_dev->props->priv, !!val); | ||
187 | else | ||
188 | return -ENOSYS; | 218 | return -ENOSYS; |
189 | 219 | ||
220 | return ir_dev->props->s_learning_mode(drv_data, !!val); | ||
221 | |||
222 | case LIRC_SET_MEASURE_CARRIER_MODE: | ||
223 | if (!ir_dev->props->s_carrier_report) | ||
224 | return -ENOSYS; | ||
225 | |||
226 | return ir_dev->props->s_carrier_report(drv_data, !!val); | ||
227 | |||
190 | /* Generic timeout support */ | 228 | /* Generic timeout support */ |
191 | case LIRC_GET_MIN_TIMEOUT: | 229 | case LIRC_GET_MIN_TIMEOUT: |
192 | if (!ir_dev->props->max_timeout) | 230 | if (!ir_dev->props->max_timeout) |
@@ -201,10 +239,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
201 | break; | 239 | break; |
202 | 240 | ||
203 | case LIRC_SET_REC_TIMEOUT: | 241 | case LIRC_SET_REC_TIMEOUT: |
204 | if (val < ir_dev->props->min_timeout || | 242 | if (!ir_dev->props->max_timeout) |
205 | val > ir_dev->props->max_timeout) | 243 | return -ENOSYS; |
206 | return -EINVAL; | 244 | |
207 | ir_dev->props->timeout = val * 1000; | 245 | tmp = val * 1000; |
246 | |||
247 | if (tmp < ir_dev->props->min_timeout || | ||
248 | tmp > ir_dev->props->max_timeout) | ||
249 | return -EINVAL; | ||
250 | |||
251 | ir_dev->props->timeout = tmp; | ||
252 | break; | ||
253 | |||
254 | case LIRC_SET_REC_TIMEOUT_REPORTS: | ||
255 | lirc->send_timeout_reports = !!val; | ||
208 | break; | 256 | break; |
209 | 257 | ||
210 | default: | 258 | default: |
@@ -212,7 +260,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
212 | } | 260 | } |
213 | 261 | ||
214 | if (_IOC_DIR(cmd) & _IOC_READ) | 262 | if (_IOC_DIR(cmd) & _IOC_READ) |
215 | ret = put_user(val, (unsigned long *)arg); | 263 | ret = put_user(val, (__u32 *)arg); |
216 | 264 | ||
217 | return ret; | 265 | return ret; |
218 | } | 266 | } |
@@ -231,6 +279,9 @@ static struct file_operations lirc_fops = { | |||
231 | .owner = THIS_MODULE, | 279 | .owner = THIS_MODULE, |
232 | .write = ir_lirc_transmit_ir, | 280 | .write = ir_lirc_transmit_ir, |
233 | .unlocked_ioctl = ir_lirc_ioctl, | 281 | .unlocked_ioctl = ir_lirc_ioctl, |
282 | #ifdef CONFIG_COMPAT | ||
283 | .compat_ioctl = ir_lirc_ioctl, | ||
284 | #endif | ||
234 | .read = lirc_dev_fop_read, | 285 | .read = lirc_dev_fop_read, |
235 | .poll = lirc_dev_fop_poll, | 286 | .poll = lirc_dev_fop_poll, |
236 | .open = lirc_dev_fop_open, | 287 | .open = lirc_dev_fop_open, |
@@ -278,6 +329,10 @@ static int ir_lirc_register(struct input_dev *input_dev) | |||
278 | if (ir_dev->props->s_learning_mode) | 329 | if (ir_dev->props->s_learning_mode) |
279 | features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; | 330 | features |= LIRC_CAN_USE_WIDEBAND_RECEIVER; |
280 | 331 | ||
332 | if (ir_dev->props->s_carrier_report) | ||
333 | features |= LIRC_CAN_MEASURE_CARRIER; | ||
334 | |||
335 | |||
281 | if (ir_dev->props->max_timeout) | 336 | if (ir_dev->props->max_timeout) |
282 | features |= LIRC_CAN_SET_REC_TIMEOUT; | 337 | features |= LIRC_CAN_SET_REC_TIMEOUT; |
283 | 338 | ||
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c index d597421d6547..70993f79c8a2 100644 --- a/drivers/media/IR/ir-nec-decoder.c +++ b/drivers/media/IR/ir-nec-decoder.c | |||
@@ -54,8 +54,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev) | |||
54 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC)) | 54 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC)) |
55 | return 0; | 55 | return 0; |
56 | 56 | ||
57 | if (IS_RESET(ev)) { | 57 | if (!is_timing_event(ev)) { |
58 | data->state = STATE_INACTIVE; | 58 | if (ev.reset) |
59 | data->state = STATE_INACTIVE; | ||
59 | return 0; | 60 | return 0; |
60 | } | 61 | } |
61 | 62 | ||
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c index 8e0e1b1f8c87..a06a07e4e0b1 100644 --- a/drivers/media/IR/ir-raw-event.c +++ b/drivers/media/IR/ir-raw-event.c | |||
@@ -39,22 +39,34 @@ static int ir_raw_event_thread(void *data) | |||
39 | struct ir_raw_event ev; | 39 | struct ir_raw_event ev; |
40 | struct ir_raw_handler *handler; | 40 | struct ir_raw_handler *handler; |
41 | struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; | 41 | struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; |
42 | int retval; | ||
42 | 43 | ||
43 | while (!kthread_should_stop()) { | 44 | while (!kthread_should_stop()) { |
44 | try_to_freeze(); | ||
45 | 45 | ||
46 | mutex_lock(&ir_raw_handler_lock); | 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); | ||
47 | 54 | ||
48 | while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { | 55 | spin_unlock_irq(&raw->lock); |
49 | list_for_each_entry(handler, &ir_raw_handler_list, list) | 56 | schedule(); |
50 | handler->decode(raw->input_dev, ev); | 57 | continue; |
51 | raw->prev_ev = ev; | ||
52 | } | 58 | } |
53 | 59 | ||
54 | mutex_unlock(&ir_raw_handler_lock); | 60 | spin_unlock_irq(&raw->lock); |
61 | |||
55 | 62 | ||
56 | set_current_state(TASK_INTERRUPTIBLE); | 63 | BUG_ON(retval != sizeof(ev)); |
57 | schedule(); | 64 | |
65 | mutex_lock(&ir_raw_handler_lock); | ||
66 | list_for_each_entry(handler, &ir_raw_handler_list, list) | ||
67 | handler->decode(raw->input_dev, ev); | ||
68 | raw->prev_ev = ev; | ||
69 | mutex_unlock(&ir_raw_handler_lock); | ||
58 | } | 70 | } |
59 | 71 | ||
60 | return 0; | 72 | return 0; |
@@ -77,7 +89,7 @@ int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev) | |||
77 | if (!ir->raw) | 89 | if (!ir->raw) |
78 | return -EINVAL; | 90 | return -EINVAL; |
79 | 91 | ||
80 | IR_dprintk(2, "sample: (05%dus %s)\n", | 92 | IR_dprintk(2, "sample: (%05dus %s)\n", |
81 | TO_US(ev->duration), TO_STR(ev->pulse)); | 93 | TO_US(ev->duration), TO_STR(ev->pulse)); |
82 | 94 | ||
83 | if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) | 95 | if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev)) |
@@ -162,7 +174,7 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev, | |||
162 | if (ir->idle && !ev->pulse) | 174 | if (ir->idle && !ev->pulse) |
163 | return 0; | 175 | return 0; |
164 | else if (ir->idle) | 176 | else if (ir->idle) |
165 | ir_raw_event_set_idle(input_dev, 0); | 177 | ir_raw_event_set_idle(input_dev, false); |
166 | 178 | ||
167 | if (!raw->this_ev.duration) { | 179 | if (!raw->this_ev.duration) { |
168 | raw->this_ev = *ev; | 180 | raw->this_ev = *ev; |
@@ -175,48 +187,35 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev, | |||
175 | 187 | ||
176 | /* Enter idle mode if nessesary */ | 188 | /* Enter idle mode if nessesary */ |
177 | if (!ev->pulse && ir->props->timeout && | 189 | if (!ev->pulse && ir->props->timeout && |
178 | raw->this_ev.duration >= ir->props->timeout) | 190 | raw->this_ev.duration >= ir->props->timeout) { |
179 | ir_raw_event_set_idle(input_dev, 1); | 191 | ir_raw_event_set_idle(input_dev, true); |
192 | } | ||
180 | return 0; | 193 | return 0; |
181 | } | 194 | } |
182 | EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); | 195 | EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter); |
183 | 196 | ||
184 | void ir_raw_event_set_idle(struct input_dev *input_dev, int idle) | 197 | /** |
198 | * ir_raw_event_set_idle() - hint the ir core if device is receiving | ||
199 | * IR data or not | ||
200 | * @input_dev: the struct input_dev device descriptor | ||
201 | * @idle: the hint value | ||
202 | */ | ||
203 | void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle) | ||
185 | { | 204 | { |
186 | struct ir_input_dev *ir = input_get_drvdata(input_dev); | 205 | struct ir_input_dev *ir = input_get_drvdata(input_dev); |
187 | struct ir_raw_event_ctrl *raw = ir->raw; | 206 | struct ir_raw_event_ctrl *raw = ir->raw; |
188 | ktime_t now; | ||
189 | u64 delta; | ||
190 | 207 | ||
191 | if (!ir->props) | 208 | if (!ir->props || !ir->raw) |
192 | return; | 209 | return; |
193 | 210 | ||
194 | if (!ir->raw) | 211 | IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave"); |
195 | goto out; | ||
196 | 212 | ||
197 | if (idle) { | 213 | if (idle) { |
198 | IR_dprintk(2, "enter idle mode\n"); | 214 | raw->this_ev.timeout = true; |
199 | raw->last_event = ktime_get(); | ||
200 | } else { | ||
201 | IR_dprintk(2, "exit idle mode\n"); | ||
202 | |||
203 | now = ktime_get(); | ||
204 | delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event)); | ||
205 | |||
206 | WARN_ON(raw->this_ev.pulse); | ||
207 | |||
208 | raw->this_ev.duration = | ||
209 | min(raw->this_ev.duration + delta, | ||
210 | (u64)IR_MAX_DURATION); | ||
211 | |||
212 | ir_raw_event_store(input_dev, &raw->this_ev); | 215 | ir_raw_event_store(input_dev, &raw->this_ev); |
213 | 216 | init_ir_raw_event(&raw->this_ev); | |
214 | if (raw->this_ev.duration == IR_MAX_DURATION) | ||
215 | ir_raw_event_reset(input_dev); | ||
216 | |||
217 | raw->this_ev.duration = 0; | ||
218 | } | 217 | } |
219 | out: | 218 | |
220 | if (ir->props->s_idle) | 219 | if (ir->props->s_idle) |
221 | ir->props->s_idle(ir->props->priv, idle); | 220 | ir->props->s_idle(ir->props->priv, idle); |
222 | ir->idle = idle; | 221 | ir->idle = idle; |
@@ -232,11 +231,14 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle); | |||
232 | void ir_raw_event_handle(struct input_dev *input_dev) | 231 | void ir_raw_event_handle(struct input_dev *input_dev) |
233 | { | 232 | { |
234 | struct ir_input_dev *ir = input_get_drvdata(input_dev); | 233 | struct ir_input_dev *ir = input_get_drvdata(input_dev); |
234 | unsigned long flags; | ||
235 | 235 | ||
236 | if (!ir->raw) | 236 | if (!ir->raw) |
237 | return; | 237 | return; |
238 | 238 | ||
239 | spin_lock_irqsave(&ir->raw->lock, flags); | ||
239 | wake_up_process(ir->raw->thread); | 240 | wake_up_process(ir->raw->thread); |
241 | spin_unlock_irqrestore(&ir->raw->lock, flags); | ||
240 | } | 242 | } |
241 | EXPORT_SYMBOL_GPL(ir_raw_event_handle); | 243 | EXPORT_SYMBOL_GPL(ir_raw_event_handle); |
242 | 244 | ||
@@ -275,6 +277,7 @@ int ir_raw_event_register(struct input_dev *input_dev) | |||
275 | return rc; | 277 | return rc; |
276 | } | 278 | } |
277 | 279 | ||
280 | spin_lock_init(&ir->raw->lock); | ||
278 | ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw, | 281 | ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw, |
279 | "rc%u", (unsigned int)ir->devno); | 282 | "rc%u", (unsigned int)ir->devno); |
280 | 283 | ||
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c index df4770d978ad..572ed4ca8c68 100644 --- a/drivers/media/IR/ir-rc5-decoder.c +++ b/drivers/media/IR/ir-rc5-decoder.c | |||
@@ -55,8 +55,9 @@ static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev) | |||
55 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5)) | 55 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5)) |
56 | return 0; | 56 | return 0; |
57 | 57 | ||
58 | if (IS_RESET(ev)) { | 58 | if (!is_timing_event(ev)) { |
59 | data->state = STATE_INACTIVE; | 59 | if (ev.reset) |
60 | data->state = STATE_INACTIVE; | ||
60 | return 0; | 61 | return 0; |
61 | } | 62 | } |
62 | 63 | ||
diff --git a/drivers/media/IR/ir-rc5-sz-decoder.c b/drivers/media/IR/ir-rc5-sz-decoder.c new file mode 100644 index 000000000000..7c413501a3f7 --- /dev/null +++ b/drivers/media/IR/ir-rc5-sz-decoder.c | |||
@@ -0,0 +1,154 @@ | |||
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 "ir-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 | |||
30 | enum 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 | * @input_dev: the struct input_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 | */ | ||
44 | static int ir_rc5_sz_decode(struct input_dev *input_dev, struct ir_raw_event ev) | ||
45 | { | ||
46 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | ||
47 | struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz; | ||
48 | u8 toggle, command, system; | ||
49 | u32 scancode; | ||
50 | |||
51 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5_SZ)) | ||
52 | return 0; | ||
53 | |||
54 | if (!is_timing_event(ev)) { | ||
55 | if (ev.reset) | ||
56 | data->state = STATE_INACTIVE; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) | ||
61 | goto out; | ||
62 | |||
63 | again: | ||
64 | IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n", | ||
65 | data->state, TO_US(ev.duration), TO_STR(ev.pulse)); | ||
66 | |||
67 | if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2)) | ||
68 | return 0; | ||
69 | |||
70 | switch (data->state) { | ||
71 | |||
72 | case STATE_INACTIVE: | ||
73 | if (!ev.pulse) | ||
74 | break; | ||
75 | |||
76 | data->state = STATE_BIT_START; | ||
77 | data->count = 1; | ||
78 | data->wanted_bits = RC5_SZ_NBITS; | ||
79 | decrease_duration(&ev, RC5_BIT_START); | ||
80 | goto again; | ||
81 | |||
82 | case STATE_BIT_START: | ||
83 | if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2)) | ||
84 | break; | ||
85 | |||
86 | data->bits <<= 1; | ||
87 | if (!ev.pulse) | ||
88 | data->bits |= 1; | ||
89 | data->count++; | ||
90 | data->state = STATE_BIT_END; | ||
91 | return 0; | ||
92 | |||
93 | case STATE_BIT_END: | ||
94 | if (!is_transition(&ev, &ir_dev->raw->prev_ev)) | ||
95 | break; | ||
96 | |||
97 | if (data->count == data->wanted_bits) | ||
98 | data->state = STATE_FINISHED; | ||
99 | else | ||
100 | data->state = STATE_BIT_START; | ||
101 | |||
102 | decrease_duration(&ev, RC5_BIT_END); | ||
103 | goto again; | ||
104 | |||
105 | case STATE_FINISHED: | ||
106 | if (ev.pulse) | ||
107 | break; | ||
108 | |||
109 | /* RC5-sz */ | ||
110 | command = (data->bits & 0x0003F) >> 0; | ||
111 | system = (data->bits & 0x02FC0) >> 6; | ||
112 | toggle = (data->bits & 0x01000) ? 1 : 0; | ||
113 | scancode = system << 6 | command; | ||
114 | |||
115 | IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n", | ||
116 | scancode, toggle); | ||
117 | |||
118 | ir_keydown(input_dev, scancode, toggle); | ||
119 | data->state = STATE_INACTIVE; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | out: | ||
124 | IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n", | ||
125 | data->state, TO_US(ev.duration), TO_STR(ev.pulse)); | ||
126 | data->state = STATE_INACTIVE; | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | |||
130 | static struct ir_raw_handler rc5_sz_handler = { | ||
131 | .protocols = IR_TYPE_RC5_SZ, | ||
132 | .decode = ir_rc5_sz_decode, | ||
133 | }; | ||
134 | |||
135 | static int __init ir_rc5_sz_decode_init(void) | ||
136 | { | ||
137 | ir_raw_handler_register(&rc5_sz_handler); | ||
138 | |||
139 | printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n"); | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void __exit ir_rc5_sz_decode_exit(void) | ||
144 | { | ||
145 | ir_raw_handler_unregister(&rc5_sz_handler); | ||
146 | } | ||
147 | |||
148 | module_init(ir_rc5_sz_decode_init); | ||
149 | module_exit(ir_rc5_sz_decode_exit); | ||
150 | |||
151 | MODULE_LICENSE("GPL"); | ||
152 | MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); | ||
153 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); | ||
154 | MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder"); | ||
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c index f1624b8279bc..d25da91f44ff 100644 --- a/drivers/media/IR/ir-rc6-decoder.c +++ b/drivers/media/IR/ir-rc6-decoder.c | |||
@@ -85,8 +85,9 @@ static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev) | |||
85 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6)) | 85 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6)) |
86 | return 0; | 86 | return 0; |
87 | 87 | ||
88 | if (IS_RESET(ev)) { | 88 | if (!is_timing_event(ev)) { |
89 | data->state = STATE_INACTIVE; | 89 | if (ev.reset) |
90 | data->state = STATE_INACTIVE; | ||
90 | return 0; | 91 | return 0; |
91 | } | 92 | } |
92 | 93 | ||
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c index b9074f07c7a0..2d15730822bc 100644 --- a/drivers/media/IR/ir-sony-decoder.c +++ b/drivers/media/IR/ir-sony-decoder.c | |||
@@ -48,8 +48,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev) | |||
48 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY)) | 48 | if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY)) |
49 | return 0; | 49 | return 0; |
50 | 50 | ||
51 | if (IS_RESET(ev)) { | 51 | if (!is_timing_event(ev)) { |
52 | data->state = STATE_INACTIVE; | 52 | if (ev.reset) |
53 | data->state = STATE_INACTIVE; | ||
53 | return 0; | 54 | return 0; |
54 | } | 55 | } |
55 | 56 | ||
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c index 46d42467f9b4..38423a8da871 100644 --- a/drivers/media/IR/ir-sysfs.c +++ b/drivers/media/IR/ir-sysfs.c | |||
@@ -43,6 +43,7 @@ static struct { | |||
43 | { IR_TYPE_RC6, "rc-6" }, | 43 | { IR_TYPE_RC6, "rc-6" }, |
44 | { IR_TYPE_JVC, "jvc" }, | 44 | { IR_TYPE_JVC, "jvc" }, |
45 | { IR_TYPE_SONY, "sony" }, | 45 | { IR_TYPE_SONY, "sony" }, |
46 | { IR_TYPE_RC5_SZ, "rc-5-sz" }, | ||
46 | { IR_TYPE_LIRC, "lirc" }, | 47 | { IR_TYPE_LIRC, "lirc" }, |
47 | }; | 48 | }; |
48 | 49 | ||
@@ -67,6 +68,10 @@ static ssize_t show_protocols(struct device *d, | |||
67 | char *tmp = buf; | 68 | char *tmp = buf; |
68 | int i; | 69 | int i; |
69 | 70 | ||
71 | /* Device is being removed */ | ||
72 | if (!ir_dev) | ||
73 | return -EINVAL; | ||
74 | |||
70 | if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { | 75 | if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) { |
71 | enabled = ir_dev->rc_tab.ir_type; | 76 | enabled = ir_dev->rc_tab.ir_type; |
72 | allowed = ir_dev->props->allowed_protos; | 77 | allowed = ir_dev->props->allowed_protos; |
@@ -122,6 +127,10 @@ static ssize_t store_protocols(struct device *d, | |||
122 | int rc, i, count = 0; | 127 | int rc, i, count = 0; |
123 | unsigned long flags; | 128 | unsigned long flags; |
124 | 129 | ||
130 | /* Device is being removed */ | ||
131 | if (!ir_dev) | ||
132 | return -EINVAL; | ||
133 | |||
125 | if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) | 134 | if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) |
126 | type = ir_dev->rc_tab.ir_type; | 135 | type = ir_dev->rc_tab.ir_type; |
127 | else if (ir_dev->raw) | 136 | else if (ir_dev->raw) |
@@ -256,8 +265,6 @@ static struct device_type rc_dev_type = { | |||
256 | */ | 265 | */ |
257 | int ir_register_class(struct input_dev *input_dev) | 266 | int ir_register_class(struct input_dev *input_dev) |
258 | { | 267 | { |
259 | int rc; | ||
260 | const char *path; | ||
261 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | 268 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); |
262 | int devno = find_first_zero_bit(&ir_core_dev_number, | 269 | int devno = find_first_zero_bit(&ir_core_dev_number, |
263 | IRRCV_NUM_DEVICES); | 270 | IRRCV_NUM_DEVICES); |
@@ -266,17 +273,28 @@ int ir_register_class(struct input_dev *input_dev) | |||
266 | return devno; | 273 | return devno; |
267 | 274 | ||
268 | ir_dev->dev.type = &rc_dev_type; | 275 | ir_dev->dev.type = &rc_dev_type; |
276 | ir_dev->devno = devno; | ||
269 | 277 | ||
270 | ir_dev->dev.class = &ir_input_class; | 278 | ir_dev->dev.class = &ir_input_class; |
271 | ir_dev->dev.parent = input_dev->dev.parent; | 279 | ir_dev->dev.parent = input_dev->dev.parent; |
280 | input_dev->dev.parent = &ir_dev->dev; | ||
272 | dev_set_name(&ir_dev->dev, "rc%d", devno); | 281 | dev_set_name(&ir_dev->dev, "rc%d", devno); |
273 | dev_set_drvdata(&ir_dev->dev, ir_dev); | 282 | dev_set_drvdata(&ir_dev->dev, ir_dev); |
274 | rc = device_register(&ir_dev->dev); | 283 | return device_register(&ir_dev->dev); |
275 | if (rc) | 284 | }; |
276 | return rc; | 285 | |
286 | /** | ||
287 | * ir_register_input - registers ir input device with input subsystem | ||
288 | * @input_dev: the struct input_dev descriptor of the device | ||
289 | */ | ||
290 | |||
291 | int ir_register_input(struct input_dev *input_dev) | ||
292 | { | ||
293 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | ||
294 | int rc; | ||
295 | const char *path; | ||
277 | 296 | ||
278 | 297 | ||
279 | input_dev->dev.parent = &ir_dev->dev; | ||
280 | rc = input_register_device(input_dev); | 298 | rc = input_register_device(input_dev); |
281 | if (rc < 0) { | 299 | if (rc < 0) { |
282 | device_del(&ir_dev->dev); | 300 | device_del(&ir_dev->dev); |
@@ -292,11 +310,9 @@ int ir_register_class(struct input_dev *input_dev) | |||
292 | path ? path : "N/A"); | 310 | path ? path : "N/A"); |
293 | kfree(path); | 311 | kfree(path); |
294 | 312 | ||
295 | ir_dev->devno = devno; | 313 | set_bit(ir_dev->devno, &ir_core_dev_number); |
296 | set_bit(devno, &ir_core_dev_number); | ||
297 | |||
298 | return 0; | 314 | return 0; |
299 | }; | 315 | } |
300 | 316 | ||
301 | /** | 317 | /** |
302 | * ir_unregister_class() - removes the sysfs for sysfs for | 318 | * ir_unregister_class() - removes the sysfs for sysfs for |
@@ -309,6 +325,7 @@ void ir_unregister_class(struct input_dev *input_dev) | |||
309 | { | 325 | { |
310 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); | 326 | struct ir_input_dev *ir_dev = input_get_drvdata(input_dev); |
311 | 327 | ||
328 | input_set_drvdata(input_dev, NULL); | ||
312 | clear_bit(ir_dev->devno, &ir_core_dev_number); | 329 | clear_bit(ir_dev->devno, &ir_core_dev_number); |
313 | input_unregister_device(input_dev); | 330 | input_unregister_device(input_dev); |
314 | device_del(&ir_dev->dev); | 331 | device_del(&ir_dev->dev); |
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile index 950e5d953c6f..3194d391bbd4 100644 --- a/drivers/media/IR/keymaps/Makefile +++ b/drivers/media/IR/keymaps/Makefile | |||
@@ -1,4 +1,6 @@ | |||
1 | obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | 1 | obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ |
2 | rc-alink-dtu-m.o \ | ||
3 | rc-anysee.o \ | ||
2 | rc-apac-viewcomp.o \ | 4 | rc-apac-viewcomp.o \ |
3 | rc-asus-pc39.o \ | 5 | rc-asus-pc39.o \ |
4 | rc-ati-tv-wonder-hd-600.o \ | 6 | rc-ati-tv-wonder-hd-600.o \ |
@@ -8,7 +10,9 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | |||
8 | rc-avermedia-dvbt.o \ | 10 | rc-avermedia-dvbt.o \ |
9 | rc-avermedia-m135a.o \ | 11 | rc-avermedia-m135a.o \ |
10 | rc-avermedia-m733a-rm-k6.o \ | 12 | rc-avermedia-m733a-rm-k6.o \ |
13 | rc-avermedia-rm-ks.o \ | ||
11 | rc-avertv-303.o \ | 14 | rc-avertv-303.o \ |
15 | rc-azurewave-ad-tu700.o \ | ||
12 | rc-behold.o \ | 16 | rc-behold.o \ |
13 | rc-behold-columbus.o \ | 17 | rc-behold-columbus.o \ |
14 | rc-budget-ci-old.o \ | 18 | rc-budget-ci-old.o \ |
@@ -16,6 +20,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | |||
16 | rc-cinergy.o \ | 20 | rc-cinergy.o \ |
17 | rc-dib0700-nec.o \ | 21 | rc-dib0700-nec.o \ |
18 | rc-dib0700-rc5.o \ | 22 | rc-dib0700-rc5.o \ |
23 | rc-digitalnow-tinytwin.o \ | ||
24 | rc-digittrade.o \ | ||
19 | rc-dm1105-nec.o \ | 25 | rc-dm1105-nec.o \ |
20 | rc-dntv-live-dvb-t.o \ | 26 | rc-dntv-live-dvb-t.o \ |
21 | rc-dntv-live-dvbt-pro.o \ | 27 | rc-dntv-live-dvbt-pro.o \ |
@@ -38,8 +44,12 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | |||
38 | rc-kaiomy.o \ | 44 | rc-kaiomy.o \ |
39 | rc-kworld-315u.o \ | 45 | rc-kworld-315u.o \ |
40 | rc-kworld-plus-tv-analog.o \ | 46 | rc-kworld-plus-tv-analog.o \ |
47 | rc-leadtek-y04g0051.o \ | ||
41 | rc-lirc.o \ | 48 | rc-lirc.o \ |
49 | rc-lme2510.o \ | ||
42 | rc-manli.o \ | 50 | rc-manli.o \ |
51 | rc-msi-digivox-ii.o \ | ||
52 | rc-msi-digivox-iii.o \ | ||
43 | rc-msi-tvanywhere.o \ | 53 | rc-msi-tvanywhere.o \ |
44 | rc-msi-tvanywhere-plus.o \ | 54 | rc-msi-tvanywhere-plus.o \ |
45 | rc-nebula.o \ | 55 | rc-nebula.o \ |
@@ -58,14 +68,18 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | |||
58 | rc-purpletv.o \ | 68 | rc-purpletv.o \ |
59 | rc-pv951.o \ | 69 | rc-pv951.o \ |
60 | rc-rc5-hauppauge-new.o \ | 70 | rc-rc5-hauppauge-new.o \ |
61 | rc-rc5-streamzap.o \ | ||
62 | rc-rc5-tv.o \ | 71 | rc-rc5-tv.o \ |
63 | rc-rc6-mce.o \ | 72 | rc-rc6-mce.o \ |
64 | rc-real-audio-220-32-keys.o \ | 73 | rc-real-audio-220-32-keys.o \ |
74 | rc-streamzap.o \ | ||
65 | rc-tbs-nec.o \ | 75 | rc-tbs-nec.o \ |
66 | rc-terratec-cinergy-xs.o \ | 76 | rc-terratec-cinergy-xs.o \ |
77 | rc-terratec-slim.o \ | ||
67 | rc-tevii-nec.o \ | 78 | rc-tevii-nec.o \ |
79 | rc-total-media-in-hand.o \ | ||
80 | rc-trekstor.o \ | ||
68 | rc-tt-1500.o \ | 81 | rc-tt-1500.o \ |
82 | rc-twinhan1027.o \ | ||
69 | rc-videomate-s350.o \ | 83 | rc-videomate-s350.o \ |
70 | rc-videomate-tv-pvr.o \ | 84 | rc-videomate-tv-pvr.o \ |
71 | rc-winfast.o \ | 85 | rc-winfast.o \ |
diff --git a/drivers/media/IR/keymaps/rc-alink-dtu-m.c b/drivers/media/IR/keymaps/rc-alink-dtu-m.c new file mode 100644 index 000000000000..ddfee7f8093d --- /dev/null +++ b/drivers/media/IR/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. */ | ||
24 | static struct ir_scancode 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 | |||
45 | static struct rc_keymap alink_dtu_m_map = { | ||
46 | .map = { | ||
47 | .scan = alink_dtu_m, | ||
48 | .size = ARRAY_SIZE(alink_dtu_m), | ||
49 | .ir_type = IR_TYPE_NEC, | ||
50 | .name = RC_MAP_ALINK_DTU_M, | ||
51 | } | ||
52 | }; | ||
53 | |||
54 | static int __init init_rc_map_alink_dtu_m(void) | ||
55 | { | ||
56 | return ir_register_map(&alink_dtu_m_map); | ||
57 | } | ||
58 | |||
59 | static void __exit exit_rc_map_alink_dtu_m(void) | ||
60 | { | ||
61 | ir_unregister_map(&alink_dtu_m_map); | ||
62 | } | ||
63 | |||
64 | module_init(init_rc_map_alink_dtu_m) | ||
65 | module_exit(exit_rc_map_alink_dtu_m) | ||
66 | |||
67 | MODULE_LICENSE("GPL"); | ||
68 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-anysee.c b/drivers/media/IR/keymaps/rc-anysee.c new file mode 100644 index 000000000000..30d70498cfed --- /dev/null +++ b/drivers/media/IR/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 | |||
23 | static struct ir_scancode 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 | |||
70 | static struct rc_keymap anysee_map = { | ||
71 | .map = { | ||
72 | .scan = anysee, | ||
73 | .size = ARRAY_SIZE(anysee), | ||
74 | .ir_type = IR_TYPE_NEC, | ||
75 | .name = RC_MAP_ANYSEE, | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | static int __init init_rc_map_anysee(void) | ||
80 | { | ||
81 | return ir_register_map(&anysee_map); | ||
82 | } | ||
83 | |||
84 | static void __exit exit_rc_map_anysee(void) | ||
85 | { | ||
86 | ir_unregister_map(&anysee_map); | ||
87 | } | ||
88 | |||
89 | module_init(init_rc_map_anysee) | ||
90 | module_exit(exit_rc_map_anysee) | ||
91 | |||
92 | MODULE_LICENSE("GPL"); | ||
93 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-asus-pc39.c b/drivers/media/IR/keymaps/rc-asus-pc39.c index 2aa068cd6c75..2996e0a3b8d5 100644 --- a/drivers/media/IR/keymaps/rc-asus-pc39.c +++ b/drivers/media/IR/keymaps/rc-asus-pc39.c | |||
@@ -20,56 +20,56 @@ | |||
20 | 20 | ||
21 | static struct ir_scancode asus_pc39[] = { | 21 | static struct ir_scancode asus_pc39[] = { |
22 | /* Keys 0 to 9 */ | 22 | /* Keys 0 to 9 */ |
23 | { 0x15, KEY_0 }, | 23 | { 0x082a, KEY_0 }, |
24 | { 0x29, KEY_1 }, | 24 | { 0x0816, KEY_1 }, |
25 | { 0x2d, KEY_2 }, | 25 | { 0x0812, KEY_2 }, |
26 | { 0x2b, KEY_3 }, | 26 | { 0x0814, KEY_3 }, |
27 | { 0x09, KEY_4 }, | 27 | { 0x0836, KEY_4 }, |
28 | { 0x0d, KEY_5 }, | 28 | { 0x0832, KEY_5 }, |
29 | { 0x0b, KEY_6 }, | 29 | { 0x0834, KEY_6 }, |
30 | { 0x31, KEY_7 }, | 30 | { 0x080e, KEY_7 }, |
31 | { 0x35, KEY_8 }, | 31 | { 0x080a, KEY_8 }, |
32 | { 0x33, KEY_9 }, | 32 | { 0x080c, KEY_9 }, |
33 | 33 | ||
34 | { 0x3e, KEY_RADIO }, /* radio */ | 34 | { 0x0801, KEY_RADIO }, /* radio */ |
35 | { 0x03, KEY_MENU }, /* dvd/menu */ | 35 | { 0x083c, KEY_MENU }, /* dvd/menu */ |
36 | { 0x2a, KEY_VOLUMEUP }, | 36 | { 0x0815, KEY_VOLUMEUP }, |
37 | { 0x19, KEY_VOLUMEDOWN }, | 37 | { 0x0826, KEY_VOLUMEDOWN }, |
38 | { 0x37, KEY_UP }, | 38 | { 0x0808, KEY_UP }, |
39 | { 0x3b, KEY_DOWN }, | 39 | { 0x0804, KEY_DOWN }, |
40 | { 0x27, KEY_LEFT }, | 40 | { 0x0818, KEY_LEFT }, |
41 | { 0x2f, KEY_RIGHT }, | 41 | { 0x0810, KEY_RIGHT }, |
42 | { 0x25, KEY_VIDEO }, /* video */ | 42 | { 0x081a, KEY_VIDEO }, /* video */ |
43 | { 0x39, KEY_AUDIO }, /* music */ | 43 | { 0x0806, KEY_AUDIO }, /* music */ |
44 | 44 | ||
45 | { 0x21, KEY_TV }, /* tv */ | 45 | { 0x081e, KEY_TV }, /* tv */ |
46 | { 0x1d, KEY_EXIT }, /* back */ | 46 | { 0x0822, KEY_EXIT }, /* back */ |
47 | { 0x0a, KEY_CHANNELUP }, /* channel / program + */ | 47 | { 0x0835, KEY_CHANNELUP }, /* channel / program + */ |
48 | { 0x1b, KEY_CHANNELDOWN }, /* channel / program - */ | 48 | { 0x0824, KEY_CHANNELDOWN }, /* channel / program - */ |
49 | { 0x1a, KEY_ENTER }, /* enter */ | 49 | { 0x0825, KEY_ENTER }, /* enter */ |
50 | 50 | ||
51 | { 0x06, KEY_PAUSE }, /* play/pause */ | 51 | { 0x0839, KEY_PAUSE }, /* play/pause */ |
52 | { 0x1e, KEY_PREVIOUS }, /* rew */ | 52 | { 0x0821, KEY_PREVIOUS }, /* rew */ |
53 | { 0x26, KEY_NEXT }, /* forward */ | 53 | { 0x0819, KEY_NEXT }, /* forward */ |
54 | { 0x0e, KEY_REWIND }, /* backward << */ | 54 | { 0x0831, KEY_REWIND }, /* backward << */ |
55 | { 0x3a, KEY_FASTFORWARD }, /* forward >> */ | 55 | { 0x0805, KEY_FASTFORWARD }, /* forward >> */ |
56 | { 0x36, KEY_STOP }, | 56 | { 0x0809, KEY_STOP }, |
57 | { 0x2e, KEY_RECORD }, /* recording */ | 57 | { 0x0811, KEY_RECORD }, /* recording */ |
58 | { 0x16, KEY_POWER }, /* the button that reads "close" */ | 58 | { 0x0829, KEY_POWER }, /* the button that reads "close" */ |
59 | 59 | ||
60 | { 0x11, KEY_ZOOM }, /* full screen */ | 60 | { 0x082e, KEY_ZOOM }, /* full screen */ |
61 | { 0x13, KEY_MACRO }, /* recall */ | 61 | { 0x082c, KEY_MACRO }, /* recall */ |
62 | { 0x23, KEY_HOME }, /* home */ | 62 | { 0x081c, KEY_HOME }, /* home */ |
63 | { 0x05, KEY_PVR }, /* picture */ | 63 | { 0x083a, KEY_PVR }, /* picture */ |
64 | { 0x3d, KEY_MUTE }, /* mute */ | 64 | { 0x0802, KEY_MUTE }, /* mute */ |
65 | { 0x01, KEY_DVD }, /* dvd */ | 65 | { 0x083e, KEY_DVD }, /* dvd */ |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static struct rc_keymap asus_pc39_map = { | 68 | static struct rc_keymap asus_pc39_map = { |
69 | .map = { | 69 | .map = { |
70 | .scan = asus_pc39, | 70 | .scan = asus_pc39, |
71 | .size = ARRAY_SIZE(asus_pc39), | 71 | .size = ARRAY_SIZE(asus_pc39), |
72 | .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */ | 72 | .ir_type = IR_TYPE_RC5, |
73 | .name = RC_MAP_ASUS_PC39, | 73 | .name = RC_MAP_ASUS_PC39, |
74 | } | 74 | } |
75 | }; | 75 | }; |
diff --git a/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c b/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c new file mode 100644 index 000000000000..9ee60906c861 --- /dev/null +++ b/drivers/media/IR/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? */ | ||
26 | static struct ir_scancode 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 | |||
56 | static struct rc_keymap avermedia_rm_ks_map = { | ||
57 | .map = { | ||
58 | .scan = avermedia_rm_ks, | ||
59 | .size = ARRAY_SIZE(avermedia_rm_ks), | ||
60 | .ir_type = IR_TYPE_NEC, | ||
61 | .name = RC_MAP_AVERMEDIA_RM_KS, | ||
62 | } | ||
63 | }; | ||
64 | |||
65 | static int __init init_rc_map_avermedia_rm_ks(void) | ||
66 | { | ||
67 | return ir_register_map(&avermedia_rm_ks_map); | ||
68 | } | ||
69 | |||
70 | static void __exit exit_rc_map_avermedia_rm_ks(void) | ||
71 | { | ||
72 | ir_unregister_map(&avermedia_rm_ks_map); | ||
73 | } | ||
74 | |||
75 | module_init(init_rc_map_avermedia_rm_ks) | ||
76 | module_exit(exit_rc_map_avermedia_rm_ks) | ||
77 | |||
78 | MODULE_LICENSE("GPL"); | ||
79 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c new file mode 100644 index 000000000000..e0876147d471 --- /dev/null +++ b/drivers/media/IR/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 | |||
23 | static struct ir_scancode 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 | |||
79 | static struct rc_keymap azurewave_ad_tu700_map = { | ||
80 | .map = { | ||
81 | .scan = azurewave_ad_tu700, | ||
82 | .size = ARRAY_SIZE(azurewave_ad_tu700), | ||
83 | .ir_type = IR_TYPE_NEC, | ||
84 | .name = RC_MAP_AZUREWAVE_AD_TU700, | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | static int __init init_rc_map_azurewave_ad_tu700(void) | ||
89 | { | ||
90 | return ir_register_map(&azurewave_ad_tu700_map); | ||
91 | } | ||
92 | |||
93 | static void __exit exit_rc_map_azurewave_ad_tu700(void) | ||
94 | { | ||
95 | ir_unregister_map(&azurewave_ad_tu700_map); | ||
96 | } | ||
97 | |||
98 | module_init(init_rc_map_azurewave_ad_tu700) | ||
99 | module_exit(exit_rc_map_azurewave_ad_tu700) | ||
100 | |||
101 | MODULE_LICENSE("GPL"); | ||
102 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c new file mode 100644 index 000000000000..63e469e2dd21 --- /dev/null +++ b/drivers/media/IR/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 | |||
23 | static struct ir_scancode 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 | |||
75 | static struct rc_keymap digitalnow_tinytwin_map = { | ||
76 | .map = { | ||
77 | .scan = digitalnow_tinytwin, | ||
78 | .size = ARRAY_SIZE(digitalnow_tinytwin), | ||
79 | .ir_type = IR_TYPE_NEC, | ||
80 | .name = RC_MAP_DIGITALNOW_TINYTWIN, | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | static int __init init_rc_map_digitalnow_tinytwin(void) | ||
85 | { | ||
86 | return ir_register_map(&digitalnow_tinytwin_map); | ||
87 | } | ||
88 | |||
89 | static void __exit exit_rc_map_digitalnow_tinytwin(void) | ||
90 | { | ||
91 | ir_unregister_map(&digitalnow_tinytwin_map); | ||
92 | } | ||
93 | |||
94 | module_init(init_rc_map_digitalnow_tinytwin) | ||
95 | module_exit(exit_rc_map_digitalnow_tinytwin) | ||
96 | |||
97 | MODULE_LICENSE("GPL"); | ||
98 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-digittrade.c b/drivers/media/IR/keymaps/rc-digittrade.c new file mode 100644 index 000000000000..5dece78e19c5 --- /dev/null +++ b/drivers/media/IR/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 */ | ||
28 | static struct ir_scancode 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 | |||
59 | static struct rc_keymap digittrade_map = { | ||
60 | .map = { | ||
61 | .scan = digittrade, | ||
62 | .size = ARRAY_SIZE(digittrade), | ||
63 | .ir_type = IR_TYPE_NEC, | ||
64 | .name = RC_MAP_DIGITTRADE, | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | static int __init init_rc_map_digittrade(void) | ||
69 | { | ||
70 | return ir_register_map(&digittrade_map); | ||
71 | } | ||
72 | |||
73 | static void __exit exit_rc_map_digittrade(void) | ||
74 | { | ||
75 | ir_unregister_map(&digittrade_map); | ||
76 | } | ||
77 | |||
78 | module_init(init_rc_map_digittrade) | ||
79 | module_exit(exit_rc_map_digittrade) | ||
80 | |||
81 | MODULE_LICENSE("GPL"); | ||
82 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c b/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c new file mode 100644 index 000000000000..7521315fd876 --- /dev/null +++ b/drivers/media/IR/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 | |||
23 | static struct ir_scancode 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 | |||
76 | static struct rc_keymap leadtek_y04g0051_map = { | ||
77 | .map = { | ||
78 | .scan = leadtek_y04g0051, | ||
79 | .size = ARRAY_SIZE(leadtek_y04g0051), | ||
80 | .ir_type = IR_TYPE_NEC, | ||
81 | .name = RC_MAP_LEADTEK_Y04G0051, | ||
82 | } | ||
83 | }; | ||
84 | |||
85 | static int __init init_rc_map_leadtek_y04g0051(void) | ||
86 | { | ||
87 | return ir_register_map(&leadtek_y04g0051_map); | ||
88 | } | ||
89 | |||
90 | static void __exit exit_rc_map_leadtek_y04g0051(void) | ||
91 | { | ||
92 | ir_unregister_map(&leadtek_y04g0051_map); | ||
93 | } | ||
94 | |||
95 | module_init(init_rc_map_leadtek_y04g0051) | ||
96 | module_exit(exit_rc_map_leadtek_y04g0051) | ||
97 | |||
98 | MODULE_LICENSE("GPL"); | ||
99 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-lme2510.c b/drivers/media/IR/keymaps/rc-lme2510.c new file mode 100644 index 000000000000..40dcf0b4e21a --- /dev/null +++ b/drivers/media/IR/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 | |||
15 | static struct ir_scancode 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 | |||
45 | static struct rc_keymap lme2510_map = { | ||
46 | .map = { | ||
47 | .scan = lme2510_rc, | ||
48 | .size = ARRAY_SIZE(lme2510_rc), | ||
49 | .ir_type = IR_TYPE_UNKNOWN, | ||
50 | .name = RC_MAP_LME2510, | ||
51 | } | ||
52 | }; | ||
53 | |||
54 | static int __init init_rc_lme2510_map(void) | ||
55 | { | ||
56 | return ir_register_map(&lme2510_map); | ||
57 | } | ||
58 | |||
59 | static void __exit exit_rc_lme2510_map(void) | ||
60 | { | ||
61 | ir_unregister_map(&lme2510_map); | ||
62 | } | ||
63 | |||
64 | module_init(init_rc_lme2510_map) | ||
65 | module_exit(exit_rc_lme2510_map) | ||
66 | |||
67 | MODULE_LICENSE("GPL"); | ||
68 | MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com"); | ||
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-ii.c b/drivers/media/IR/keymaps/rc-msi-digivox-ii.c new file mode 100644 index 000000000000..67237fbf9e4b --- /dev/null +++ b/drivers/media/IR/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 | |||
23 | static struct ir_scancode 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 | |||
44 | static struct rc_keymap msi_digivox_ii_map = { | ||
45 | .map = { | ||
46 | .scan = msi_digivox_ii, | ||
47 | .size = ARRAY_SIZE(msi_digivox_ii), | ||
48 | .ir_type = IR_TYPE_NEC, | ||
49 | .name = RC_MAP_MSI_DIGIVOX_II, | ||
50 | } | ||
51 | }; | ||
52 | |||
53 | static int __init init_rc_map_msi_digivox_ii(void) | ||
54 | { | ||
55 | return ir_register_map(&msi_digivox_ii_map); | ||
56 | } | ||
57 | |||
58 | static void __exit exit_rc_map_msi_digivox_ii(void) | ||
59 | { | ||
60 | ir_unregister_map(&msi_digivox_ii_map); | ||
61 | } | ||
62 | |||
63 | module_init(init_rc_map_msi_digivox_ii) | ||
64 | module_exit(exit_rc_map_msi_digivox_ii) | ||
65 | |||
66 | MODULE_LICENSE("GPL"); | ||
67 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-iii.c b/drivers/media/IR/keymaps/rc-msi-digivox-iii.c new file mode 100644 index 000000000000..882056e52ef9 --- /dev/null +++ b/drivers/media/IR/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. */ | ||
27 | static struct ir_scancode 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 | |||
62 | static struct rc_keymap msi_digivox_iii_map = { | ||
63 | .map = { | ||
64 | .scan = msi_digivox_iii, | ||
65 | .size = ARRAY_SIZE(msi_digivox_iii), | ||
66 | .ir_type = IR_TYPE_NEC, | ||
67 | .name = RC_MAP_MSI_DIGIVOX_III, | ||
68 | } | ||
69 | }; | ||
70 | |||
71 | static int __init init_rc_map_msi_digivox_iii(void) | ||
72 | { | ||
73 | return ir_register_map(&msi_digivox_iii_map); | ||
74 | } | ||
75 | |||
76 | static void __exit exit_rc_map_msi_digivox_iii(void) | ||
77 | { | ||
78 | ir_unregister_map(&msi_digivox_iii_map); | ||
79 | } | ||
80 | |||
81 | module_init(init_rc_map_msi_digivox_iii) | ||
82 | module_exit(exit_rc_map_msi_digivox_iii) | ||
83 | |||
84 | MODULE_LICENSE("GPL"); | ||
85 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-rc5-streamzap.c b/drivers/media/IR/keymaps/rc-rc5-streamzap.c deleted file mode 100644 index 4c19c58b46d8..000000000000 --- a/drivers/media/IR/keymaps/rc-rc5-streamzap.c +++ /dev/null | |||
@@ -1,81 +0,0 @@ | |||
1 | /* rc-rc5-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 | |||
14 | static struct ir_scancode rc5_streamzap[] = { | ||
15 | /* | ||
16 | * FIXME: The Streamzap remote isn't actually true RC-5, it has an extra | ||
17 | * bit in it, which presently throws the in-kernel RC-5 decoder for a loop. | ||
18 | * We either have to enhance the decoder to support it, add a new decoder, | ||
19 | * or just rely on lirc userspace decoding. | ||
20 | */ | ||
21 | { 0x00, KEY_NUMERIC_0 }, | ||
22 | { 0x01, KEY_NUMERIC_1 }, | ||
23 | { 0x02, KEY_NUMERIC_2 }, | ||
24 | { 0x03, KEY_NUMERIC_3 }, | ||
25 | { 0x04, KEY_NUMERIC_4 }, | ||
26 | { 0x05, KEY_NUMERIC_5 }, | ||
27 | { 0x06, KEY_NUMERIC_6 }, | ||
28 | { 0x07, KEY_NUMERIC_7 }, | ||
29 | { 0x08, KEY_NUMERIC_8 }, | ||
30 | { 0x0a, KEY_POWER }, | ||
31 | { 0x0b, KEY_MUTE }, | ||
32 | { 0x0c, KEY_CHANNELUP }, | ||
33 | { 0x0d, KEY_VOLUMEUP }, | ||
34 | { 0x0e, KEY_CHANNELDOWN }, | ||
35 | { 0x0f, KEY_VOLUMEDOWN }, | ||
36 | { 0x10, KEY_UP }, | ||
37 | { 0x11, KEY_LEFT }, | ||
38 | { 0x12, KEY_OK }, | ||
39 | { 0x13, KEY_RIGHT }, | ||
40 | { 0x14, KEY_DOWN }, | ||
41 | { 0x15, KEY_MENU }, | ||
42 | { 0x16, KEY_EXIT }, | ||
43 | { 0x17, KEY_PLAY }, | ||
44 | { 0x18, KEY_PAUSE }, | ||
45 | { 0x19, KEY_STOP }, | ||
46 | { 0x1a, KEY_BACK }, | ||
47 | { 0x1b, KEY_FORWARD }, | ||
48 | { 0x1c, KEY_RECORD }, | ||
49 | { 0x1d, KEY_REWIND }, | ||
50 | { 0x1e, KEY_FASTFORWARD }, | ||
51 | { 0x20, KEY_RED }, | ||
52 | { 0x21, KEY_GREEN }, | ||
53 | { 0x22, KEY_YELLOW }, | ||
54 | { 0x23, KEY_BLUE }, | ||
55 | |||
56 | }; | ||
57 | |||
58 | static struct rc_keymap rc5_streamzap_map = { | ||
59 | .map = { | ||
60 | .scan = rc5_streamzap, | ||
61 | .size = ARRAY_SIZE(rc5_streamzap), | ||
62 | .ir_type = IR_TYPE_RC5, | ||
63 | .name = RC_MAP_RC5_STREAMZAP, | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | static int __init init_rc_map_rc5_streamzap(void) | ||
68 | { | ||
69 | return ir_register_map(&rc5_streamzap_map); | ||
70 | } | ||
71 | |||
72 | static void __exit exit_rc_map_rc5_streamzap(void) | ||
73 | { | ||
74 | ir_unregister_map(&rc5_streamzap_map); | ||
75 | } | ||
76 | |||
77 | module_init(init_rc_map_rc5_streamzap) | ||
78 | module_exit(exit_rc_map_rc5_streamzap) | ||
79 | |||
80 | MODULE_LICENSE("GPL"); | ||
81 | MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c index 39557ad401b6..1b7adabbcee9 100644 --- a/drivers/media/IR/keymaps/rc-rc6-mce.c +++ b/drivers/media/IR/keymaps/rc-rc6-mce.c | |||
@@ -12,76 +12,78 @@ | |||
12 | #include <media/rc-map.h> | 12 | #include <media/rc-map.h> |
13 | 13 | ||
14 | static struct ir_scancode rc6_mce[] = { | 14 | static struct ir_scancode rc6_mce[] = { |
15 | { 0x800f0415, KEY_REWIND }, | ||
16 | { 0x800f0414, KEY_FASTFORWARD }, | ||
17 | { 0x800f041b, KEY_PREVIOUS }, | ||
18 | { 0x800f041a, KEY_NEXT }, | ||
19 | 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 }, | ||
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 }, | ||
20 | { 0x800f0416, KEY_PLAY }, | 41 | { 0x800f0416, KEY_PLAY }, |
42 | { 0x800f0417, KEY_RECORD }, | ||
21 | { 0x800f0418, KEY_PAUSE }, | 43 | { 0x800f0418, KEY_PAUSE }, |
22 | { 0x800f046e, KEY_PLAYPAUSE }, | 44 | { 0x800f046e, KEY_PLAYPAUSE }, |
23 | { 0x800f0419, KEY_STOP }, | 45 | { 0x800f0419, KEY_STOP }, |
24 | { 0x800f0417, KEY_RECORD }, | 46 | { 0x800f041a, KEY_NEXT }, |
47 | { 0x800f041b, KEY_PREVIOUS }, | ||
48 | { 0x800f041c, KEY_NUMERIC_POUND }, | ||
49 | { 0x800f041d, KEY_NUMERIC_STAR }, | ||
25 | 50 | ||
26 | { 0x800f041e, KEY_UP }, | 51 | { 0x800f041e, KEY_UP }, |
27 | { 0x800f041f, KEY_DOWN }, | 52 | { 0x800f041f, KEY_DOWN }, |
28 | { 0x800f0420, KEY_LEFT }, | 53 | { 0x800f0420, KEY_LEFT }, |
29 | { 0x800f0421, KEY_RIGHT }, | 54 | { 0x800f0421, KEY_RIGHT }, |
30 | 55 | ||
31 | { 0x800f040b, KEY_ENTER }, | ||
32 | { 0x800f0422, KEY_OK }, | 56 | { 0x800f0422, KEY_OK }, |
33 | { 0x800f0423, KEY_EXIT }, | 57 | { 0x800f0423, KEY_EXIT }, |
34 | { 0x800f040a, KEY_DELETE }, | 58 | { 0x800f0424, KEY_DVD }, |
59 | { 0x800f0425, KEY_TUNER }, /* LiveTV */ | ||
60 | { 0x800f0426, KEY_EPG }, /* Guide */ | ||
61 | { 0x800f0427, KEY_ZOOM }, /* Aspect */ | ||
35 | 62 | ||
36 | { 0x800f040e, KEY_MUTE }, | ||
37 | { 0x800f0410, KEY_VOLUMEUP }, | ||
38 | { 0x800f0411, KEY_VOLUMEDOWN }, | ||
39 | { 0x800f0412, KEY_CHANNELUP }, | ||
40 | { 0x800f0413, KEY_CHANNELDOWN }, | ||
41 | { 0x800f043a, KEY_BRIGHTNESSUP }, | 63 | { 0x800f043a, KEY_BRIGHTNESSUP }, |
42 | { 0x800f0480, KEY_BRIGHTNESSDOWN }, | ||
43 | |||
44 | { 0x800f0401, KEY_NUMERIC_1 }, | ||
45 | { 0x800f0402, KEY_NUMERIC_2 }, | ||
46 | { 0x800f0403, KEY_NUMERIC_3 }, | ||
47 | { 0x800f0404, KEY_NUMERIC_4 }, | ||
48 | { 0x800f0405, KEY_NUMERIC_5 }, | ||
49 | { 0x800f0406, KEY_NUMERIC_6 }, | ||
50 | { 0x800f0407, KEY_NUMERIC_7 }, | ||
51 | { 0x800f0408, KEY_NUMERIC_8 }, | ||
52 | { 0x800f0409, KEY_NUMERIC_9 }, | ||
53 | { 0x800f0400, KEY_NUMERIC_0 }, | ||
54 | |||
55 | { 0x800f041d, KEY_NUMERIC_STAR }, | ||
56 | { 0x800f041c, KEY_NUMERIC_POUND }, | ||
57 | 64 | ||
58 | { 0x800f0446, KEY_TV }, | 65 | { 0x800f0446, KEY_TV }, |
59 | { 0x800f0447, KEY_AUDIO }, /* My Music */ | 66 | { 0x800f0447, KEY_AUDIO }, /* My Music */ |
60 | { 0x800f0448, KEY_PVR }, /* RecordedTV */ | 67 | { 0x800f0448, KEY_PVR }, /* RecordedTV */ |
61 | { 0x800f0449, KEY_CAMERA }, | 68 | { 0x800f0449, KEY_CAMERA }, |
62 | { 0x800f044a, KEY_VIDEO }, | 69 | { 0x800f044a, KEY_VIDEO }, |
63 | { 0x800f0424, KEY_DVD }, | ||
64 | { 0x800f0425, KEY_TUNER }, /* LiveTV */ | ||
65 | { 0x800f0450, KEY_RADIO }, | ||
66 | |||
67 | { 0x800f044c, KEY_LANGUAGE }, | 70 | { 0x800f044c, KEY_LANGUAGE }, |
68 | { 0x800f0427, KEY_ZOOM }, /* Aspect */ | 71 | { 0x800f044d, KEY_TITLE }, |
72 | { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */ | ||
69 | 73 | ||
74 | { 0x800f0450, KEY_RADIO }, | ||
75 | |||
76 | { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ | ||
70 | { 0x800f045b, KEY_RED }, | 77 | { 0x800f045b, KEY_RED }, |
71 | { 0x800f045c, KEY_GREEN }, | 78 | { 0x800f045c, KEY_GREEN }, |
72 | { 0x800f045d, KEY_YELLOW }, | 79 | { 0x800f045d, KEY_YELLOW }, |
73 | { 0x800f045e, KEY_BLUE }, | 80 | { 0x800f045e, KEY_BLUE }, |
74 | 81 | ||
75 | { 0x800f040f, KEY_INFO }, | 82 | { 0x800f046e, KEY_PLAYPAUSE }, |
76 | { 0x800f0426, KEY_EPG }, /* Guide */ | 83 | { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */ |
77 | { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */ | ||
78 | { 0x800f044d, KEY_TITLE }, | ||
79 | |||
80 | { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */ | ||
81 | |||
82 | { 0x800f040c, KEY_POWER }, | ||
83 | { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ | ||
84 | 84 | ||
85 | { 0x800f0480, KEY_BRIGHTNESSDOWN }, | ||
86 | { 0x800f0481, KEY_PLAYPAUSE }, | ||
85 | }; | 87 | }; |
86 | 88 | ||
87 | static struct rc_keymap rc6_mce_map = { | 89 | static struct rc_keymap rc6_mce_map = { |
diff --git a/drivers/media/IR/keymaps/rc-streamzap.c b/drivers/media/IR/keymaps/rc-streamzap.c new file mode 100644 index 000000000000..df32013a321c --- /dev/null +++ b/drivers/media/IR/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 | |||
14 | static struct ir_scancode 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 | |||
59 | static struct rc_keymap streamzap_map = { | ||
60 | .map = { | ||
61 | .scan = streamzap, | ||
62 | .size = ARRAY_SIZE(streamzap), | ||
63 | .ir_type = IR_TYPE_RC5_SZ, | ||
64 | .name = RC_MAP_STREAMZAP, | ||
65 | } | ||
66 | }; | ||
67 | |||
68 | static int __init init_rc_map_streamzap(void) | ||
69 | { | ||
70 | return ir_register_map(&streamzap_map); | ||
71 | } | ||
72 | |||
73 | static void __exit exit_rc_map_streamzap(void) | ||
74 | { | ||
75 | ir_unregister_map(&streamzap_map); | ||
76 | } | ||
77 | |||
78 | module_init(init_rc_map_streamzap) | ||
79 | module_exit(exit_rc_map_streamzap) | ||
80 | |||
81 | MODULE_LICENSE("GPL"); | ||
82 | MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-terratec-slim.c b/drivers/media/IR/keymaps/rc-terratec-slim.c new file mode 100644 index 000000000000..10dee4c1deff --- /dev/null +++ b/drivers/media/IR/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. */ | ||
25 | static struct ir_scancode 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 | |||
56 | static struct rc_keymap terratec_slim_map = { | ||
57 | .map = { | ||
58 | .scan = terratec_slim, | ||
59 | .size = ARRAY_SIZE(terratec_slim), | ||
60 | .ir_type = IR_TYPE_NEC, | ||
61 | .name = RC_MAP_TERRATEC_SLIM, | ||
62 | } | ||
63 | }; | ||
64 | |||
65 | static int __init init_rc_map_terratec_slim(void) | ||
66 | { | ||
67 | return ir_register_map(&terratec_slim_map); | ||
68 | } | ||
69 | |||
70 | static void __exit exit_rc_map_terratec_slim(void) | ||
71 | { | ||
72 | ir_unregister_map(&terratec_slim_map); | ||
73 | } | ||
74 | |||
75 | module_init(init_rc_map_terratec_slim) | ||
76 | module_exit(exit_rc_map_terratec_slim) | ||
77 | |||
78 | MODULE_LICENSE("GPL"); | ||
79 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-total-media-in-hand.c b/drivers/media/IR/keymaps/rc-total-media-in-hand.c new file mode 100644 index 000000000000..fd1985763781 --- /dev/null +++ b/drivers/media/IR/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 */ | ||
24 | static struct ir_scancode 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 | |||
62 | static struct rc_keymap total_media_in_hand_map = { | ||
63 | .map = { | ||
64 | .scan = total_media_in_hand, | ||
65 | .size = ARRAY_SIZE(total_media_in_hand), | ||
66 | .ir_type = IR_TYPE_NEC, | ||
67 | .name = RC_MAP_TOTAL_MEDIA_IN_HAND, | ||
68 | } | ||
69 | }; | ||
70 | |||
71 | static int __init init_rc_map_total_media_in_hand(void) | ||
72 | { | ||
73 | return ir_register_map(&total_media_in_hand_map); | ||
74 | } | ||
75 | |||
76 | static void __exit exit_rc_map_total_media_in_hand(void) | ||
77 | { | ||
78 | ir_unregister_map(&total_media_in_hand_map); | ||
79 | } | ||
80 | |||
81 | module_init(init_rc_map_total_media_in_hand) | ||
82 | module_exit(exit_rc_map_total_media_in_hand) | ||
83 | |||
84 | MODULE_LICENSE("GPL"); | ||
85 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-trekstor.c b/drivers/media/IR/keymaps/rc-trekstor.c new file mode 100644 index 000000000000..91092caca452 --- /dev/null +++ b/drivers/media/IR/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> */ | ||
26 | static struct ir_scancode 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 | |||
57 | static struct rc_keymap trekstor_map = { | ||
58 | .map = { | ||
59 | .scan = trekstor, | ||
60 | .size = ARRAY_SIZE(trekstor), | ||
61 | .ir_type = IR_TYPE_NEC, | ||
62 | .name = RC_MAP_TREKSTOR, | ||
63 | } | ||
64 | }; | ||
65 | |||
66 | static int __init init_rc_map_trekstor(void) | ||
67 | { | ||
68 | return ir_register_map(&trekstor_map); | ||
69 | } | ||
70 | |||
71 | static void __exit exit_rc_map_trekstor(void) | ||
72 | { | ||
73 | ir_unregister_map(&trekstor_map); | ||
74 | } | ||
75 | |||
76 | module_init(init_rc_map_trekstor) | ||
77 | module_exit(exit_rc_map_trekstor) | ||
78 | |||
79 | MODULE_LICENSE("GPL"); | ||
80 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
diff --git a/drivers/media/IR/keymaps/rc-twinhan1027.c b/drivers/media/IR/keymaps/rc-twinhan1027.c new file mode 100644 index 000000000000..0b5d356c2d84 --- /dev/null +++ b/drivers/media/IR/keymaps/rc-twinhan1027.c | |||
@@ -0,0 +1,87 @@ | |||
1 | #include <media/rc-map.h> | ||
2 | |||
3 | static struct ir_scancode 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 | |||
64 | static struct rc_keymap twinhan_vp1027_map = { | ||
65 | .map = { | ||
66 | .scan = twinhan_vp1027, | ||
67 | .size = ARRAY_SIZE(twinhan_vp1027), | ||
68 | .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */ | ||
69 | .name = RC_MAP_TWINHAN_VP1027_DVBS, | ||
70 | } | ||
71 | }; | ||
72 | |||
73 | static int __init init_rc_map_twinhan_vp1027(void) | ||
74 | { | ||
75 | return ir_register_map(&twinhan_vp1027_map); | ||
76 | } | ||
77 | |||
78 | static void __exit exit_rc_map_twinhan_vp1027(void) | ||
79 | { | ||
80 | ir_unregister_map(&twinhan_vp1027_map); | ||
81 | } | ||
82 | |||
83 | module_init(init_rc_map_twinhan_vp1027) | ||
84 | module_exit(exit_rc_map_twinhan_vp1027) | ||
85 | |||
86 | MODULE_LICENSE("GPL"); | ||
87 | MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>"); | ||
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c index 202581808bdc..8418b14ee4d2 100644 --- a/drivers/media/IR/lirc_dev.c +++ b/drivers/media/IR/lirc_dev.c | |||
@@ -57,13 +57,12 @@ struct irctl { | |||
57 | 57 | ||
58 | struct task_struct *task; | 58 | struct task_struct *task; |
59 | long jiffies_to_wait; | 59 | long jiffies_to_wait; |
60 | |||
61 | struct cdev cdev; | ||
62 | }; | 60 | }; |
63 | 61 | ||
64 | static DEFINE_MUTEX(lirc_dev_lock); | 62 | static DEFINE_MUTEX(lirc_dev_lock); |
65 | 63 | ||
66 | static struct irctl *irctls[MAX_IRCTL_DEVICES]; | 64 | static struct irctl *irctls[MAX_IRCTL_DEVICES]; |
65 | static struct cdev cdevs[MAX_IRCTL_DEVICES]; | ||
67 | 66 | ||
68 | /* Only used for sysfs but defined to void otherwise */ | 67 | /* Only used for sysfs but defined to void otherwise */ |
69 | static struct class *lirc_class; | 68 | static struct class *lirc_class; |
@@ -71,15 +70,13 @@ static struct class *lirc_class; | |||
71 | /* helper function | 70 | /* helper function |
72 | * initializes the irctl structure | 71 | * initializes the irctl structure |
73 | */ | 72 | */ |
74 | static void init_irctl(struct irctl *ir) | 73 | static void lirc_irctl_init(struct irctl *ir) |
75 | { | 74 | { |
76 | dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n", | ||
77 | ir->d.name, ir->d.minor); | ||
78 | mutex_init(&ir->irctl_lock); | 75 | mutex_init(&ir->irctl_lock); |
79 | ir->d.minor = NOPLUG; | 76 | ir->d.minor = NOPLUG; |
80 | } | 77 | } |
81 | 78 | ||
82 | static void cleanup(struct irctl *ir) | 79 | static void lirc_irctl_cleanup(struct irctl *ir) |
83 | { | 80 | { |
84 | dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); | 81 | dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor); |
85 | 82 | ||
@@ -96,7 +93,7 @@ static void cleanup(struct irctl *ir) | |||
96 | * reads key codes from driver and puts them into buffer | 93 | * reads key codes from driver and puts them into buffer |
97 | * returns 0 on success | 94 | * returns 0 on success |
98 | */ | 95 | */ |
99 | static int add_to_buf(struct irctl *ir) | 96 | static int lirc_add_to_buf(struct irctl *ir) |
100 | { | 97 | { |
101 | if (ir->d.add_to_buf) { | 98 | if (ir->d.add_to_buf) { |
102 | int res = -ENODATA; | 99 | int res = -ENODATA; |
@@ -139,7 +136,7 @@ static int lirc_thread(void *irctl) | |||
139 | } | 136 | } |
140 | if (kthread_should_stop()) | 137 | if (kthread_should_stop()) |
141 | break; | 138 | break; |
142 | if (!add_to_buf(ir)) | 139 | if (!lirc_add_to_buf(ir)) |
143 | wake_up_interruptible(&ir->buf->wait_poll); | 140 | wake_up_interruptible(&ir->buf->wait_poll); |
144 | } else { | 141 | } else { |
145 | set_current_state(TASK_INTERRUPTIBLE); | 142 | set_current_state(TASK_INTERRUPTIBLE); |
@@ -154,12 +151,15 @@ static int lirc_thread(void *irctl) | |||
154 | } | 151 | } |
155 | 152 | ||
156 | 153 | ||
157 | static struct file_operations fops = { | 154 | static struct file_operations lirc_dev_fops = { |
158 | .owner = THIS_MODULE, | 155 | .owner = THIS_MODULE, |
159 | .read = lirc_dev_fop_read, | 156 | .read = lirc_dev_fop_read, |
160 | .write = lirc_dev_fop_write, | 157 | .write = lirc_dev_fop_write, |
161 | .poll = lirc_dev_fop_poll, | 158 | .poll = lirc_dev_fop_poll, |
162 | .unlocked_ioctl = lirc_dev_fop_ioctl, | 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, | 163 | .open = lirc_dev_fop_open, |
164 | .release = lirc_dev_fop_close, | 164 | .release = lirc_dev_fop_close, |
165 | .llseek = noop_llseek, | 165 | .llseek = noop_llseek, |
@@ -169,19 +169,20 @@ static int lirc_cdev_add(struct irctl *ir) | |||
169 | { | 169 | { |
170 | int retval; | 170 | int retval; |
171 | struct lirc_driver *d = &ir->d; | 171 | struct lirc_driver *d = &ir->d; |
172 | struct cdev *cdev = &cdevs[d->minor]; | ||
172 | 173 | ||
173 | if (d->fops) { | 174 | if (d->fops) { |
174 | cdev_init(&ir->cdev, d->fops); | 175 | cdev_init(cdev, d->fops); |
175 | ir->cdev.owner = d->owner; | 176 | cdev->owner = d->owner; |
176 | } else { | 177 | } else { |
177 | cdev_init(&ir->cdev, &fops); | 178 | cdev_init(cdev, &lirc_dev_fops); |
178 | ir->cdev.owner = THIS_MODULE; | 179 | cdev->owner = THIS_MODULE; |
179 | } | 180 | } |
180 | kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); | 181 | kobject_set_name(&cdev->kobj, "lirc%d", d->minor); |
181 | 182 | ||
182 | retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); | 183 | retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); |
183 | if (retval) | 184 | if (retval) |
184 | kobject_put(&ir->cdev.kobj); | 185 | kobject_put(&cdev->kobj); |
185 | 186 | ||
186 | return retval; | 187 | return retval; |
187 | } | 188 | } |
@@ -202,6 +203,12 @@ int lirc_register_driver(struct lirc_driver *d) | |||
202 | goto out; | 203 | goto out; |
203 | } | 204 | } |
204 | 205 | ||
206 | if (!d->dev) { | ||
207 | printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__); | ||
208 | err = -EINVAL; | ||
209 | goto out; | ||
210 | } | ||
211 | |||
205 | if (MAX_IRCTL_DEVICES <= d->minor) { | 212 | if (MAX_IRCTL_DEVICES <= d->minor) { |
206 | dev_err(d->dev, "lirc_dev: lirc_register_driver: " | 213 | dev_err(d->dev, "lirc_dev: lirc_register_driver: " |
207 | "\"minor\" must be between 0 and %d (%d)!\n", | 214 | "\"minor\" must be between 0 and %d (%d)!\n", |
@@ -277,7 +284,7 @@ int lirc_register_driver(struct lirc_driver *d) | |||
277 | err = -ENOMEM; | 284 | err = -ENOMEM; |
278 | goto out_lock; | 285 | goto out_lock; |
279 | } | 286 | } |
280 | init_irctl(ir); | 287 | lirc_irctl_init(ir); |
281 | irctls[minor] = ir; | 288 | irctls[minor] = ir; |
282 | d->minor = minor; | 289 | d->minor = minor; |
283 | 290 | ||
@@ -316,7 +323,6 @@ int lirc_register_driver(struct lirc_driver *d) | |||
316 | d->features = LIRC_CAN_REC_LIRCCODE; | 323 | d->features = LIRC_CAN_REC_LIRCCODE; |
317 | 324 | ||
318 | ir->d = *d; | 325 | ir->d = *d; |
319 | ir->d.minor = minor; | ||
320 | 326 | ||
321 | device_create(lirc_class, ir->d.dev, | 327 | device_create(lirc_class, ir->d.dev, |
322 | MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, | 328 | MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, |
@@ -357,21 +363,28 @@ EXPORT_SYMBOL(lirc_register_driver); | |||
357 | int lirc_unregister_driver(int minor) | 363 | int lirc_unregister_driver(int minor) |
358 | { | 364 | { |
359 | struct irctl *ir; | 365 | struct irctl *ir; |
366 | struct cdev *cdev; | ||
360 | 367 | ||
361 | if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { | 368 | if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { |
362 | printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " | 369 | printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " |
363 | "\"minor (%d)\" must be between 0 and %d!\n", | 370 | "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1); |
364 | minor, MAX_IRCTL_DEVICES-1); | ||
365 | return -EBADRQC; | 371 | return -EBADRQC; |
366 | } | 372 | } |
367 | 373 | ||
368 | ir = irctls[minor]; | 374 | ir = irctls[minor]; |
375 | if (!ir) { | ||
376 | printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct " | ||
377 | "for minor %d!\n", __func__, minor); | ||
378 | return -ENOENT; | ||
379 | } | ||
380 | |||
381 | cdev = &cdevs[minor]; | ||
369 | 382 | ||
370 | mutex_lock(&lirc_dev_lock); | 383 | mutex_lock(&lirc_dev_lock); |
371 | 384 | ||
372 | if (ir->d.minor != minor) { | 385 | if (ir->d.minor != minor) { |
373 | printk(KERN_ERR "lirc_dev: lirc_unregister_driver: " | 386 | printk(KERN_ERR "lirc_dev: %s: minor (%d) device not " |
374 | "minor (%d) device not registered!", minor); | 387 | "registered!\n", __func__, minor); |
375 | mutex_unlock(&lirc_dev_lock); | 388 | mutex_unlock(&lirc_dev_lock); |
376 | return -ENOENT; | 389 | return -ENOENT; |
377 | } | 390 | } |
@@ -390,12 +403,11 @@ int lirc_unregister_driver(int minor) | |||
390 | wake_up_interruptible(&ir->buf->wait_poll); | 403 | wake_up_interruptible(&ir->buf->wait_poll); |
391 | mutex_lock(&ir->irctl_lock); | 404 | mutex_lock(&ir->irctl_lock); |
392 | ir->d.set_use_dec(ir->d.data); | 405 | ir->d.set_use_dec(ir->d.data); |
393 | module_put(ir->d.owner); | 406 | module_put(cdev->owner); |
394 | mutex_unlock(&ir->irctl_lock); | 407 | mutex_unlock(&ir->irctl_lock); |
395 | cdev_del(&ir->cdev); | ||
396 | } else { | 408 | } else { |
397 | cleanup(ir); | 409 | lirc_irctl_cleanup(ir); |
398 | cdev_del(&ir->cdev); | 410 | cdev_del(cdev); |
399 | kfree(ir); | 411 | kfree(ir); |
400 | irctls[minor] = NULL; | 412 | irctls[minor] = NULL; |
401 | } | 413 | } |
@@ -409,6 +421,7 @@ EXPORT_SYMBOL(lirc_unregister_driver); | |||
409 | int lirc_dev_fop_open(struct inode *inode, struct file *file) | 421 | int lirc_dev_fop_open(struct inode *inode, struct file *file) |
410 | { | 422 | { |
411 | struct irctl *ir; | 423 | struct irctl *ir; |
424 | struct cdev *cdev; | ||
412 | int retval = 0; | 425 | int retval = 0; |
413 | 426 | ||
414 | if (iminor(inode) >= MAX_IRCTL_DEVICES) { | 427 | if (iminor(inode) >= MAX_IRCTL_DEVICES) { |
@@ -425,7 +438,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) | |||
425 | retval = -ENODEV; | 438 | retval = -ENODEV; |
426 | goto error; | 439 | goto error; |
427 | } | 440 | } |
428 | file->private_data = ir; | ||
429 | 441 | ||
430 | dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); | 442 | dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); |
431 | 443 | ||
@@ -439,13 +451,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) | |||
439 | goto error; | 451 | goto error; |
440 | } | 452 | } |
441 | 453 | ||
442 | if (try_module_get(ir->d.owner)) { | 454 | cdev = &cdevs[iminor(inode)]; |
443 | ++ir->open; | 455 | if (try_module_get(cdev->owner)) { |
456 | ir->open++; | ||
444 | retval = ir->d.set_use_inc(ir->d.data); | 457 | retval = ir->d.set_use_inc(ir->d.data); |
445 | 458 | ||
446 | if (retval) { | 459 | if (retval) { |
447 | module_put(ir->d.owner); | 460 | module_put(cdev->owner); |
448 | --ir->open; | 461 | ir->open--; |
449 | } else { | 462 | } else { |
450 | lirc_buffer_clear(ir->buf); | 463 | lirc_buffer_clear(ir->buf); |
451 | } | 464 | } |
@@ -469,17 +482,24 @@ EXPORT_SYMBOL(lirc_dev_fop_open); | |||
469 | int lirc_dev_fop_close(struct inode *inode, struct file *file) | 482 | int lirc_dev_fop_close(struct inode *inode, struct file *file) |
470 | { | 483 | { |
471 | struct irctl *ir = irctls[iminor(inode)]; | 484 | struct irctl *ir = irctls[iminor(inode)]; |
485 | struct cdev *cdev = &cdevs[iminor(inode)]; | ||
486 | |||
487 | if (!ir) { | ||
488 | printk(KERN_ERR "%s: called with invalid irctl\n", __func__); | ||
489 | return -EINVAL; | ||
490 | } | ||
472 | 491 | ||
473 | dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); | 492 | dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor); |
474 | 493 | ||
475 | WARN_ON(mutex_lock_killable(&lirc_dev_lock)); | 494 | WARN_ON(mutex_lock_killable(&lirc_dev_lock)); |
476 | 495 | ||
477 | --ir->open; | 496 | ir->open--; |
478 | if (ir->attached) { | 497 | if (ir->attached) { |
479 | ir->d.set_use_dec(ir->d.data); | 498 | ir->d.set_use_dec(ir->d.data); |
480 | module_put(ir->d.owner); | 499 | module_put(cdev->owner); |
481 | } else { | 500 | } else { |
482 | cleanup(ir); | 501 | lirc_irctl_cleanup(ir); |
502 | cdev_del(cdev); | ||
483 | irctls[ir->d.minor] = NULL; | 503 | irctls[ir->d.minor] = NULL; |
484 | kfree(ir); | 504 | kfree(ir); |
485 | } | 505 | } |
@@ -495,6 +515,11 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) | |||
495 | struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; | 515 | struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; |
496 | unsigned int ret; | 516 | unsigned int ret; |
497 | 517 | ||
518 | if (!ir) { | ||
519 | printk(KERN_ERR "%s: called with invalid irctl\n", __func__); | ||
520 | return POLLERR; | ||
521 | } | ||
522 | |||
498 | dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); | 523 | dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor); |
499 | 524 | ||
500 | if (!ir->attached) { | 525 | if (!ir->attached) { |
@@ -521,9 +546,14 @@ EXPORT_SYMBOL(lirc_dev_fop_poll); | |||
521 | 546 | ||
522 | long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 547 | long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
523 | { | 548 | { |
524 | unsigned long mode; | 549 | __u32 mode; |
525 | int result = 0; | 550 | int result = 0; |
526 | struct irctl *ir = file->private_data; | 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 | } | ||
527 | 557 | ||
528 | dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", | 558 | dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", |
529 | ir->d.name, ir->d.minor, cmd); | 559 | ir->d.name, ir->d.minor, cmd); |
@@ -538,7 +568,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
538 | 568 | ||
539 | switch (cmd) { | 569 | switch (cmd) { |
540 | case LIRC_GET_FEATURES: | 570 | case LIRC_GET_FEATURES: |
541 | result = put_user(ir->d.features, (unsigned long *)arg); | 571 | result = put_user(ir->d.features, (__u32 *)arg); |
542 | break; | 572 | break; |
543 | case LIRC_GET_REC_MODE: | 573 | case LIRC_GET_REC_MODE: |
544 | if (!(ir->d.features & LIRC_CAN_REC_MASK)) { | 574 | if (!(ir->d.features & LIRC_CAN_REC_MASK)) { |
@@ -548,7 +578,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
548 | 578 | ||
549 | result = put_user(LIRC_REC2MODE | 579 | result = put_user(LIRC_REC2MODE |
550 | (ir->d.features & LIRC_CAN_REC_MASK), | 580 | (ir->d.features & LIRC_CAN_REC_MASK), |
551 | (unsigned long *)arg); | 581 | (__u32 *)arg); |
552 | break; | 582 | break; |
553 | case LIRC_SET_REC_MODE: | 583 | case LIRC_SET_REC_MODE: |
554 | if (!(ir->d.features & LIRC_CAN_REC_MASK)) { | 584 | if (!(ir->d.features & LIRC_CAN_REC_MASK)) { |
@@ -556,7 +586,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
556 | break; | 586 | break; |
557 | } | 587 | } |
558 | 588 | ||
559 | result = get_user(mode, (unsigned long *)arg); | 589 | result = get_user(mode, (__u32 *)arg); |
560 | if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) | 590 | if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) |
561 | result = -EINVAL; | 591 | result = -EINVAL; |
562 | /* | 592 | /* |
@@ -565,7 +595,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
565 | */ | 595 | */ |
566 | break; | 596 | break; |
567 | case LIRC_GET_LENGTH: | 597 | case LIRC_GET_LENGTH: |
568 | result = put_user(ir->d.code_length, (unsigned long *)arg); | 598 | result = put_user(ir->d.code_length, (__u32 *)arg); |
569 | break; | 599 | break; |
570 | case LIRC_GET_MIN_TIMEOUT: | 600 | case LIRC_GET_MIN_TIMEOUT: |
571 | if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || | 601 | if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || |
@@ -574,7 +604,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
574 | break; | 604 | break; |
575 | } | 605 | } |
576 | 606 | ||
577 | result = put_user(ir->d.min_timeout, (unsigned long *)arg); | 607 | result = put_user(ir->d.min_timeout, (__u32 *)arg); |
578 | break; | 608 | break; |
579 | case LIRC_GET_MAX_TIMEOUT: | 609 | case LIRC_GET_MAX_TIMEOUT: |
580 | if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || | 610 | if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || |
@@ -583,7 +613,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
583 | break; | 613 | break; |
584 | } | 614 | } |
585 | 615 | ||
586 | result = put_user(ir->d.max_timeout, (unsigned long *)arg); | 616 | result = put_user(ir->d.max_timeout, (__u32 *)arg); |
587 | break; | 617 | break; |
588 | default: | 618 | default: |
589 | result = -EINVAL; | 619 | result = -EINVAL; |
@@ -604,12 +634,21 @@ ssize_t lirc_dev_fop_read(struct file *file, | |||
604 | loff_t *ppos) | 634 | loff_t *ppos) |
605 | { | 635 | { |
606 | struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; | 636 | struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; |
607 | unsigned char buf[ir->chunk_size]; | 637 | unsigned char *buf; |
608 | int ret = 0, written = 0; | 638 | int ret = 0, written = 0; |
609 | DECLARE_WAITQUEUE(wait, current); | 639 | DECLARE_WAITQUEUE(wait, current); |
610 | 640 | ||
641 | if (!ir) { | ||
642 | printk(KERN_ERR "%s: called with invalid irctl\n", __func__); | ||
643 | return -ENODEV; | ||
644 | } | ||
645 | |||
611 | dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); | 646 | dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); |
612 | 647 | ||
648 | buf = kzalloc(ir->chunk_size, GFP_KERNEL); | ||
649 | if (!buf) | ||
650 | return -ENOMEM; | ||
651 | |||
613 | if (mutex_lock_interruptible(&ir->irctl_lock)) | 652 | if (mutex_lock_interruptible(&ir->irctl_lock)) |
614 | return -ERESTARTSYS; | 653 | return -ERESTARTSYS; |
615 | if (!ir->attached) { | 654 | if (!ir->attached) { |
@@ -681,6 +720,7 @@ ssize_t lirc_dev_fop_read(struct file *file, | |||
681 | mutex_unlock(&ir->irctl_lock); | 720 | mutex_unlock(&ir->irctl_lock); |
682 | 721 | ||
683 | out_unlocked: | 722 | out_unlocked: |
723 | kfree(buf); | ||
684 | dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", | 724 | dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n", |
685 | ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); | 725 | ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret); |
686 | 726 | ||
@@ -709,6 +749,11 @@ ssize_t lirc_dev_fop_write(struct file *file, const char *buffer, | |||
709 | { | 749 | { |
710 | struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; | 750 | struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)]; |
711 | 751 | ||
752 | if (!ir) { | ||
753 | printk(KERN_ERR "%s: called with invalid irctl\n", __func__); | ||
754 | return -ENODEV; | ||
755 | } | ||
756 | |||
712 | dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); | 757 | dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor); |
713 | 758 | ||
714 | if (!ir->attached) | 759 | if (!ir->attached) |
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c index bc620e10ef77..9dce684fd231 100644 --- a/drivers/media/IR/mceusb.c +++ b/drivers/media/IR/mceusb.c | |||
@@ -46,24 +46,58 @@ | |||
46 | "device driver" | 46 | "device driver" |
47 | #define DRIVER_NAME "mceusb" | 47 | #define DRIVER_NAME "mceusb" |
48 | 48 | ||
49 | #define USB_BUFLEN 32 /* USB reception buffer length */ | 49 | #define USB_BUFLEN 32 /* USB reception buffer length */ |
50 | #define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ | 50 | #define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */ |
51 | #define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ | 51 | #define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */ |
52 | 52 | ||
53 | /* MCE constants */ | 53 | /* MCE constants */ |
54 | #define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ | 54 | #define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */ |
55 | #define MCE_TIME_UNIT 50 /* Approx 50us resolution */ | 55 | #define MCE_TIME_UNIT 50 /* Approx 50us resolution */ |
56 | #define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ | 56 | #define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */ |
57 | #define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ | 57 | #define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */ |
58 | #define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ | 58 | #define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */ |
59 | #define MCE_CONTROL_HEADER 0x9F /* MCE status header */ | 59 | #define MCE_IRDATA_TRAILER 0x80 /* End of IR data */ |
60 | #define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ | 60 | #define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */ |
61 | #define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ | 61 | #define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */ |
62 | #define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */ | 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 */ | 63 | #define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */ |
64 | #define MCE_PULSE_MASK 0x7F /* Pulse mask */ | 64 | #define MCE_PULSE_MASK 0x7f /* Pulse mask */ |
65 | #define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */ | 65 | #define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */ |
66 | #define MCE_PACKET_LENGTH_MASK 0x1F /* Packet length mask */ | 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_PING 0x03 /* Ping device */ | ||
78 | #define MCE_CMD_UNKNOWN 0x04 /* Unknown */ | ||
79 | #define MCE_CMD_UNKNOWN2 0x05 /* Unknown */ | ||
80 | #define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */ | ||
81 | #define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */ | ||
82 | #define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */ | ||
83 | #define MCE_CMD_UNKNOWN3 0x09 /* Unknown */ | ||
84 | #define MCE_CMD_UNKNOWN4 0x0a /* Unknown */ | ||
85 | #define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */ | ||
86 | #define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */ | ||
87 | #define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */ | ||
88 | #define MCE_CMD_UNKNOWN5 0x0e /* Unknown */ | ||
89 | #define MCE_CMD_UNKNOWN6 0x0f /* Unknown */ | ||
90 | #define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */ | ||
91 | #define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */ | ||
92 | #define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */ | ||
93 | #define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */ | ||
94 | #define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */ | ||
95 | #define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */ | ||
96 | #define MCE_CMD_UNKNOWN7 0x18 /* Unknown */ | ||
97 | #define MCE_CMD_UNKNOWN8 0x19 /* Unknown */ | ||
98 | #define MCE_CMD_UNKNOWN9 0x1b /* Unknown */ | ||
99 | #define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */ | ||
100 | #define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */ | ||
67 | 101 | ||
68 | 102 | ||
69 | /* module parameters */ | 103 | /* module parameters */ |
@@ -104,14 +138,64 @@ static int debug; | |||
104 | #define VENDOR_NORTHSTAR 0x04eb | 138 | #define VENDOR_NORTHSTAR 0x04eb |
105 | #define VENDOR_REALTEK 0x0bda | 139 | #define VENDOR_REALTEK 0x0bda |
106 | #define VENDOR_TIVO 0x105a | 140 | #define VENDOR_TIVO 0x105a |
141 | #define VENDOR_CONEXANT 0x0572 | ||
142 | |||
143 | enum mceusb_model_type { | ||
144 | MCE_GEN2 = 0, /* Most boards */ | ||
145 | MCE_GEN1, | ||
146 | MCE_GEN3, | ||
147 | MCE_GEN2_TX_INV, | ||
148 | POLARIS_EVK, | ||
149 | }; | ||
150 | |||
151 | struct mceusb_model { | ||
152 | u32 mce_gen1:1; | ||
153 | u32 mce_gen2:1; | ||
154 | u32 mce_gen3:1; | ||
155 | u32 tx_mask_inverted:1; | ||
156 | u32 is_polaris:1; | ||
157 | |||
158 | const char *rc_map; /* Allow specify a per-board map */ | ||
159 | const char *name; /* per-board name */ | ||
160 | }; | ||
161 | |||
162 | static const struct mceusb_model mceusb_model[] = { | ||
163 | [MCE_GEN1] = { | ||
164 | .mce_gen1 = 1, | ||
165 | .tx_mask_inverted = 1, | ||
166 | }, | ||
167 | [MCE_GEN2] = { | ||
168 | .mce_gen2 = 1, | ||
169 | }, | ||
170 | [MCE_GEN2_TX_INV] = { | ||
171 | .mce_gen2 = 1, | ||
172 | .tx_mask_inverted = 1, | ||
173 | }, | ||
174 | [MCE_GEN3] = { | ||
175 | .mce_gen3 = 1, | ||
176 | .tx_mask_inverted = 1, | ||
177 | }, | ||
178 | [POLARIS_EVK] = { | ||
179 | .is_polaris = 1, | ||
180 | /* | ||
181 | * In fact, the EVK is shipped without | ||
182 | * remotes, but we should have something handy, | ||
183 | * to allow testing it | ||
184 | */ | ||
185 | .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW, | ||
186 | .name = "cx231xx MCE IR", | ||
187 | }, | ||
188 | }; | ||
107 | 189 | ||
108 | static struct usb_device_id mceusb_dev_table[] = { | 190 | static struct usb_device_id mceusb_dev_table[] = { |
109 | /* Original Microsoft MCE IR Transceiver (often HP-branded) */ | 191 | /* Original Microsoft MCE IR Transceiver (often HP-branded) */ |
110 | { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, | 192 | { USB_DEVICE(VENDOR_MICROSOFT, 0x006d), |
193 | .driver_info = MCE_GEN1 }, | ||
111 | /* Philips Infrared Transceiver - Sahara branded */ | 194 | /* Philips Infrared Transceiver - Sahara branded */ |
112 | { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, | 195 | { USB_DEVICE(VENDOR_PHILIPS, 0x0608) }, |
113 | /* Philips Infrared Transceiver - HP branded */ | 196 | /* Philips Infrared Transceiver - HP branded */ |
114 | { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, | 197 | { USB_DEVICE(VENDOR_PHILIPS, 0x060c), |
198 | .driver_info = MCE_GEN2_TX_INV }, | ||
115 | /* Philips SRM5100 */ | 199 | /* Philips SRM5100 */ |
116 | { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, | 200 | { USB_DEVICE(VENDOR_PHILIPS, 0x060d) }, |
117 | /* Philips Infrared Transceiver - Omaura */ | 201 | /* Philips Infrared Transceiver - Omaura */ |
@@ -127,11 +211,14 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
127 | /* Realtek MCE IR Receiver */ | 211 | /* Realtek MCE IR Receiver */ |
128 | { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, | 212 | { USB_DEVICE(VENDOR_REALTEK, 0x0161) }, |
129 | /* SMK/Toshiba G83C0004D410 */ | 213 | /* SMK/Toshiba G83C0004D410 */ |
130 | { USB_DEVICE(VENDOR_SMK, 0x031d) }, | 214 | { USB_DEVICE(VENDOR_SMK, 0x031d), |
215 | .driver_info = MCE_GEN2_TX_INV }, | ||
131 | /* SMK eHome Infrared Transceiver (Sony VAIO) */ | 216 | /* SMK eHome Infrared Transceiver (Sony VAIO) */ |
132 | { USB_DEVICE(VENDOR_SMK, 0x0322) }, | 217 | { USB_DEVICE(VENDOR_SMK, 0x0322), |
218 | .driver_info = MCE_GEN2_TX_INV }, | ||
133 | /* bundled with Hauppauge PVR-150 */ | 219 | /* bundled with Hauppauge PVR-150 */ |
134 | { USB_DEVICE(VENDOR_SMK, 0x0334) }, | 220 | { USB_DEVICE(VENDOR_SMK, 0x0334), |
221 | .driver_info = MCE_GEN2_TX_INV }, | ||
135 | /* SMK eHome Infrared Transceiver */ | 222 | /* SMK eHome Infrared Transceiver */ |
136 | { USB_DEVICE(VENDOR_SMK, 0x0338) }, | 223 | { USB_DEVICE(VENDOR_SMK, 0x0338) }, |
137 | /* Tatung eHome Infrared Transceiver */ | 224 | /* Tatung eHome Infrared Transceiver */ |
@@ -145,17 +232,23 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
145 | /* Mitsumi */ | 232 | /* Mitsumi */ |
146 | { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, | 233 | { USB_DEVICE(VENDOR_MITSUMI, 0x2501) }, |
147 | /* Topseed eHome Infrared Transceiver */ | 234 | /* Topseed eHome Infrared Transceiver */ |
148 | { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, | 235 | { USB_DEVICE(VENDOR_TOPSEED, 0x0001), |
236 | .driver_info = MCE_GEN2_TX_INV }, | ||
149 | /* Topseed HP eHome Infrared Transceiver */ | 237 | /* Topseed HP eHome Infrared Transceiver */ |
150 | { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, | 238 | { USB_DEVICE(VENDOR_TOPSEED, 0x0006), |
239 | .driver_info = MCE_GEN2_TX_INV }, | ||
151 | /* Topseed eHome Infrared Transceiver */ | 240 | /* Topseed eHome Infrared Transceiver */ |
152 | { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, | 241 | { USB_DEVICE(VENDOR_TOPSEED, 0x0007), |
242 | .driver_info = MCE_GEN2_TX_INV }, | ||
153 | /* Topseed eHome Infrared Transceiver */ | 243 | /* Topseed eHome Infrared Transceiver */ |
154 | { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, | 244 | { USB_DEVICE(VENDOR_TOPSEED, 0x0008), |
245 | .driver_info = MCE_GEN3 }, | ||
155 | /* Topseed eHome Infrared Transceiver */ | 246 | /* Topseed eHome Infrared Transceiver */ |
156 | { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, | 247 | { USB_DEVICE(VENDOR_TOPSEED, 0x000a), |
248 | .driver_info = MCE_GEN2_TX_INV }, | ||
157 | /* Topseed eHome Infrared Transceiver */ | 249 | /* Topseed eHome Infrared Transceiver */ |
158 | { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, | 250 | { USB_DEVICE(VENDOR_TOPSEED, 0x0011), |
251 | .driver_info = MCE_GEN2_TX_INV }, | ||
159 | /* Ricavision internal Infrared Transceiver */ | 252 | /* Ricavision internal Infrared Transceiver */ |
160 | { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, | 253 | { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, |
161 | /* Itron ione Libra Q-11 */ | 254 | /* Itron ione Libra Q-11 */ |
@@ -185,7 +278,8 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
185 | /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ | 278 | /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */ |
186 | { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, | 279 | { USB_DEVICE(VENDOR_FINTEK, 0x0702) }, |
187 | /* Pinnacle Remote Kit */ | 280 | /* Pinnacle Remote Kit */ |
188 | { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, | 281 | { USB_DEVICE(VENDOR_PINNACLE, 0x0225), |
282 | .driver_info = MCE_GEN3 }, | ||
189 | /* Elitegroup Computer Systems IR */ | 283 | /* Elitegroup Computer Systems IR */ |
190 | { USB_DEVICE(VENDOR_ECS, 0x0f38) }, | 284 | { USB_DEVICE(VENDOR_ECS, 0x0f38) }, |
191 | /* Wistron Corp. eHome Infrared Receiver */ | 285 | /* Wistron Corp. eHome Infrared Receiver */ |
@@ -198,37 +292,13 @@ static struct usb_device_id mceusb_dev_table[] = { | |||
198 | { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, | 292 | { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) }, |
199 | /* TiVo PC IR Receiver */ | 293 | /* TiVo PC IR Receiver */ |
200 | { USB_DEVICE(VENDOR_TIVO, 0x2000) }, | 294 | { USB_DEVICE(VENDOR_TIVO, 0x2000) }, |
295 | /* Conexant SDK */ | ||
296 | { USB_DEVICE(VENDOR_CONEXANT, 0x58a1), | ||
297 | .driver_info = POLARIS_EVK }, | ||
201 | /* Terminating entry */ | 298 | /* Terminating entry */ |
202 | { } | 299 | { } |
203 | }; | 300 | }; |
204 | 301 | ||
205 | static struct usb_device_id gen3_list[] = { | ||
206 | { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, | ||
207 | { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, | ||
208 | {} | ||
209 | }; | ||
210 | |||
211 | static struct usb_device_id microsoft_gen1_list[] = { | ||
212 | { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, | ||
213 | {} | ||
214 | }; | ||
215 | |||
216 | static struct usb_device_id std_tx_mask_list[] = { | ||
217 | { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) }, | ||
218 | { USB_DEVICE(VENDOR_PHILIPS, 0x060c) }, | ||
219 | { USB_DEVICE(VENDOR_SMK, 0x031d) }, | ||
220 | { USB_DEVICE(VENDOR_SMK, 0x0322) }, | ||
221 | { USB_DEVICE(VENDOR_SMK, 0x0334) }, | ||
222 | { USB_DEVICE(VENDOR_TOPSEED, 0x0001) }, | ||
223 | { USB_DEVICE(VENDOR_TOPSEED, 0x0006) }, | ||
224 | { USB_DEVICE(VENDOR_TOPSEED, 0x0007) }, | ||
225 | { USB_DEVICE(VENDOR_TOPSEED, 0x0008) }, | ||
226 | { USB_DEVICE(VENDOR_TOPSEED, 0x000a) }, | ||
227 | { USB_DEVICE(VENDOR_TOPSEED, 0x0011) }, | ||
228 | { USB_DEVICE(VENDOR_PINNACLE, 0x0225) }, | ||
229 | {} | ||
230 | }; | ||
231 | |||
232 | /* data structure for each usb transceiver */ | 302 | /* data structure for each usb transceiver */ |
233 | struct mceusb_dev { | 303 | struct mceusb_dev { |
234 | /* ir-core bits */ | 304 | /* ir-core bits */ |
@@ -248,8 +318,15 @@ struct mceusb_dev { | |||
248 | /* buffers and dma */ | 318 | /* buffers and dma */ |
249 | unsigned char *buf_in; | 319 | unsigned char *buf_in; |
250 | unsigned int len_in; | 320 | unsigned int len_in; |
251 | u8 cmd; /* MCE command type */ | 321 | |
252 | u8 rem; /* Remaining IR data bytes in packet */ | 322 | enum { |
323 | CMD_HEADER = 0, | ||
324 | SUBCMD, | ||
325 | CMD_DATA, | ||
326 | PARSE_IRDATA, | ||
327 | } parser_state; | ||
328 | u8 cmd, rem; /* Remaining IR data bytes in packet */ | ||
329 | |||
253 | dma_addr_t dma_in; | 330 | dma_addr_t dma_in; |
254 | dma_addr_t dma_out; | 331 | dma_addr_t dma_out; |
255 | 332 | ||
@@ -257,7 +334,6 @@ struct mceusb_dev { | |||
257 | u32 connected:1; | 334 | u32 connected:1; |
258 | u32 tx_mask_inverted:1; | 335 | u32 tx_mask_inverted:1; |
259 | u32 microsoft_gen1:1; | 336 | u32 microsoft_gen1:1; |
260 | u32 reserved:29; | ||
261 | } flags; | 337 | } flags; |
262 | 338 | ||
263 | /* transmit support */ | 339 | /* transmit support */ |
@@ -267,6 +343,7 @@ struct mceusb_dev { | |||
267 | 343 | ||
268 | char name[128]; | 344 | char name[128]; |
269 | char phys[64]; | 345 | char phys[64]; |
346 | enum mceusb_model_type model; | ||
270 | }; | 347 | }; |
271 | 348 | ||
272 | /* | 349 | /* |
@@ -291,43 +368,81 @@ struct mceusb_dev { | |||
291 | * - SET_RX_TIMEOUT sets the receiver timeout | 368 | * - SET_RX_TIMEOUT sets the receiver timeout |
292 | * - SET_RX_SENSOR sets which receiver sensor to use | 369 | * - SET_RX_SENSOR sets which receiver sensor to use |
293 | */ | 370 | */ |
294 | static char DEVICE_RESET[] = {0x00, 0xff, 0xaa}; | 371 | static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER, |
295 | static char GET_REVISION[] = {0xff, 0x0b}; | 372 | MCE_CMD_DEVICE_RESET}; |
296 | static char GET_UNKNOWN[] = {0xff, 0x18}; | 373 | static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION}; |
297 | static char GET_UNKNOWN2[] = {0x9f, 0x05}; | 374 | static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7}; |
298 | static char GET_CARRIER_FREQ[] = {0x9f, 0x07}; | 375 | static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2}; |
299 | static char GET_RX_TIMEOUT[] = {0x9f, 0x0d}; | 376 | static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER}; |
300 | static char GET_TX_BITMASK[] = {0x9f, 0x13}; | 377 | static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT}; |
301 | static char GET_RX_SENSOR[] = {0x9f, 0x15}; | 378 | static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK}; |
379 | static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR}; | ||
302 | /* sub in desired values in lower byte or bytes for full command */ | 380 | /* sub in desired values in lower byte or bytes for full command */ |
303 | /* FIXME: make use of these for transmit. | 381 | /* FIXME: make use of these for transmit. |
304 | static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00}; | 382 | static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, |
305 | static char SET_TX_BITMASK[] = {0x9f, 0x08, 0x00}; | 383 | MCE_CMD_S_CARRIER, 0x00, 0x00}; |
306 | static char SET_RX_TIMEOUT[] = {0x9f, 0x0c, 0x00, 0x00}; | 384 | static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00}; |
307 | static char SET_RX_SENSOR[] = {0x9f, 0x14, 0x00}; | 385 | static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, |
386 | MCE_CMD_S_TIMEOUT, 0x00, 0x00}; | ||
387 | static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER, | ||
388 | MCE_CMD_S_RXSENSOR, 0x00}; | ||
308 | */ | 389 | */ |
309 | 390 | ||
391 | static int mceusb_cmdsize(u8 cmd, u8 subcmd) | ||
392 | { | ||
393 | int datasize = 0; | ||
394 | |||
395 | switch (cmd) { | ||
396 | case MCE_COMMAND_NULL: | ||
397 | if (subcmd == MCE_HW_CMD_HEADER) | ||
398 | datasize = 1; | ||
399 | break; | ||
400 | case MCE_HW_CMD_HEADER: | ||
401 | switch (subcmd) { | ||
402 | case MCE_CMD_G_REVISION: | ||
403 | datasize = 2; | ||
404 | break; | ||
405 | } | ||
406 | case MCE_COMMAND_HEADER: | ||
407 | switch (subcmd) { | ||
408 | case MCE_CMD_UNKNOWN: | ||
409 | case MCE_CMD_S_CARRIER: | ||
410 | case MCE_CMD_S_TIMEOUT: | ||
411 | case MCE_CMD_G_RXSENSOR: | ||
412 | datasize = 2; | ||
413 | break; | ||
414 | case MCE_CMD_S_TXMASK: | ||
415 | case MCE_CMD_S_RXSENSOR: | ||
416 | datasize = 1; | ||
417 | break; | ||
418 | } | ||
419 | } | ||
420 | return datasize; | ||
421 | } | ||
422 | |||
310 | static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, | 423 | static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, |
311 | int len, bool out) | 424 | int offset, int len, bool out) |
312 | { | 425 | { |
313 | char codes[USB_BUFLEN * 3 + 1]; | 426 | char codes[USB_BUFLEN * 3 + 1]; |
314 | char inout[9]; | 427 | char inout[9]; |
315 | int i; | ||
316 | u8 cmd, subcmd, data1, data2; | 428 | u8 cmd, subcmd, data1, data2; |
317 | struct device *dev = ir->dev; | 429 | struct device *dev = ir->dev; |
318 | int idx = 0; | 430 | int i, start, skip = 0; |
431 | |||
432 | if (!debug) | ||
433 | return; | ||
319 | 434 | ||
320 | /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ | 435 | /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ |
321 | if (ir->flags.microsoft_gen1 && !out) | 436 | if (ir->flags.microsoft_gen1 && !out) |
322 | idx = 2; | 437 | skip = 2; |
323 | 438 | ||
324 | if (len <= idx) | 439 | if (len <= skip) |
325 | return; | 440 | return; |
326 | 441 | ||
327 | for (i = 0; i < len && i < USB_BUFLEN; i++) | 442 | for (i = 0; i < len && i < USB_BUFLEN; i++) |
328 | snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF); | 443 | snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff); |
329 | 444 | ||
330 | dev_info(dev, "%sx data: %s (length=%d)\n", | 445 | dev_info(dev, "%sx data: %s(length=%d)\n", |
331 | (out ? "t" : "r"), codes, len); | 446 | (out ? "t" : "r"), codes, len); |
332 | 447 | ||
333 | if (out) | 448 | if (out) |
@@ -335,91 +450,93 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, | |||
335 | else | 450 | else |
336 | strcpy(inout, "Got\0"); | 451 | strcpy(inout, "Got\0"); |
337 | 452 | ||
338 | cmd = buf[idx] & 0xff; | 453 | start = offset + skip; |
339 | subcmd = buf[idx + 1] & 0xff; | 454 | cmd = buf[start] & 0xff; |
340 | data1 = buf[idx + 2] & 0xff; | 455 | subcmd = buf[start + 1] & 0xff; |
341 | data2 = buf[idx + 3] & 0xff; | 456 | data1 = buf[start + 2] & 0xff; |
457 | data2 = buf[start + 3] & 0xff; | ||
342 | 458 | ||
343 | switch (cmd) { | 459 | switch (cmd) { |
344 | case 0x00: | 460 | case MCE_COMMAND_NULL: |
345 | if (subcmd == 0xff && data1 == 0xaa) | 461 | if ((subcmd == MCE_HW_CMD_HEADER) && |
462 | (data1 == MCE_CMD_DEVICE_RESET)) | ||
346 | dev_info(dev, "Device reset requested\n"); | 463 | dev_info(dev, "Device reset requested\n"); |
347 | else | 464 | else |
348 | dev_info(dev, "Unknown command 0x%02x 0x%02x\n", | 465 | dev_info(dev, "Unknown command 0x%02x 0x%02x\n", |
349 | cmd, subcmd); | 466 | cmd, subcmd); |
350 | break; | 467 | break; |
351 | case 0xff: | 468 | case MCE_HW_CMD_HEADER: |
352 | switch (subcmd) { | 469 | switch (subcmd) { |
353 | case 0x0b: | 470 | case MCE_CMD_G_REVISION: |
354 | if (len == 2) | 471 | if (len == 2) |
355 | dev_info(dev, "Get hw/sw rev?\n"); | 472 | dev_info(dev, "Get hw/sw rev?\n"); |
356 | else | 473 | else |
357 | dev_info(dev, "hw/sw rev 0x%02x 0x%02x " | 474 | dev_info(dev, "hw/sw rev 0x%02x 0x%02x " |
358 | "0x%02x 0x%02x\n", data1, data2, | 475 | "0x%02x 0x%02x\n", data1, data2, |
359 | buf[idx + 4], buf[idx + 5]); | 476 | buf[start + 4], buf[start + 5]); |
360 | break; | 477 | break; |
361 | case 0xaa: | 478 | case MCE_CMD_DEVICE_RESET: |
362 | dev_info(dev, "Device reset requested\n"); | 479 | dev_info(dev, "Device reset requested\n"); |
363 | break; | 480 | break; |
364 | case 0xfe: | 481 | case MCE_RSP_CMD_INVALID: |
365 | dev_info(dev, "Previous command not supported\n"); | 482 | dev_info(dev, "Previous command not supported\n"); |
366 | break; | 483 | break; |
367 | case 0x18: | 484 | case MCE_CMD_UNKNOWN7: |
368 | case 0x1b: | 485 | case MCE_CMD_UNKNOWN9: |
369 | default: | 486 | default: |
370 | dev_info(dev, "Unknown command 0x%02x 0x%02x\n", | 487 | dev_info(dev, "Unknown command 0x%02x 0x%02x\n", |
371 | cmd, subcmd); | 488 | cmd, subcmd); |
372 | break; | 489 | break; |
373 | } | 490 | } |
374 | break; | 491 | break; |
375 | case 0x9f: | 492 | case MCE_COMMAND_HEADER: |
376 | switch (subcmd) { | 493 | switch (subcmd) { |
377 | case 0x03: | 494 | case MCE_CMD_PING: |
378 | dev_info(dev, "Ping\n"); | 495 | dev_info(dev, "Ping\n"); |
379 | break; | 496 | break; |
380 | case 0x04: | 497 | case MCE_CMD_UNKNOWN: |
381 | dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", | 498 | dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n", |
382 | data1, data2); | 499 | data1, data2); |
383 | break; | 500 | break; |
384 | case 0x06: | 501 | case MCE_CMD_S_CARRIER: |
385 | dev_info(dev, "%s carrier mode and freq of " | 502 | dev_info(dev, "%s carrier mode and freq of " |
386 | "0x%02x 0x%02x\n", inout, data1, data2); | 503 | "0x%02x 0x%02x\n", inout, data1, data2); |
387 | break; | 504 | break; |
388 | case 0x07: | 505 | case MCE_CMD_G_CARRIER: |
389 | dev_info(dev, "Get carrier mode and freq\n"); | 506 | dev_info(dev, "Get carrier mode and freq\n"); |
390 | break; | 507 | break; |
391 | case 0x08: | 508 | case MCE_CMD_S_TXMASK: |
392 | dev_info(dev, "%s transmit blaster mask of 0x%02x\n", | 509 | dev_info(dev, "%s transmit blaster mask of 0x%02x\n", |
393 | inout, data1); | 510 | inout, data1); |
394 | break; | 511 | break; |
395 | case 0x0c: | 512 | case MCE_CMD_S_TIMEOUT: |
396 | /* value is in units of 50us, so x*50/100 or x/2 ms */ | 513 | /* value is in units of 50us, so x*50/100 or x/2 ms */ |
397 | dev_info(dev, "%s receive timeout of %d ms\n", | 514 | dev_info(dev, "%s receive timeout of %d ms\n", |
398 | inout, ((data1 << 8) | data2) / 2); | 515 | inout, ((data1 << 8) | data2) / 2); |
399 | break; | 516 | break; |
400 | case 0x0d: | 517 | case MCE_CMD_G_TIMEOUT: |
401 | dev_info(dev, "Get receive timeout\n"); | 518 | dev_info(dev, "Get receive timeout\n"); |
402 | break; | 519 | break; |
403 | case 0x13: | 520 | case MCE_CMD_G_TXMASK: |
404 | dev_info(dev, "Get transmit blaster mask\n"); | 521 | dev_info(dev, "Get transmit blaster mask\n"); |
405 | break; | 522 | break; |
406 | case 0x14: | 523 | case MCE_CMD_S_RXSENSOR: |
407 | dev_info(dev, "%s %s-range receive sensor in use\n", | 524 | dev_info(dev, "%s %s-range receive sensor in use\n", |
408 | inout, data1 == 0x02 ? "short" : "long"); | 525 | inout, data1 == 0x02 ? "short" : "long"); |
409 | break; | 526 | break; |
410 | case 0x15: | 527 | case MCE_CMD_G_RXSENSOR: |
411 | if (len == 2) | 528 | if (len == 2) |
412 | dev_info(dev, "Get receive sensor\n"); | 529 | dev_info(dev, "Get receive sensor\n"); |
413 | else | 530 | else |
414 | dev_info(dev, "Received pulse count is %d\n", | 531 | dev_info(dev, "Received pulse count is %d\n", |
415 | ((data1 << 8) | data2)); | 532 | ((data1 << 8) | data2)); |
416 | break; | 533 | break; |
417 | case 0xfe: | 534 | case MCE_RSP_CMD_INVALID: |
418 | dev_info(dev, "Error! Hardware is likely wedged...\n"); | 535 | dev_info(dev, "Error! Hardware is likely wedged...\n"); |
419 | break; | 536 | break; |
420 | case 0x05: | 537 | case MCE_CMD_UNKNOWN2: |
421 | case 0x09: | 538 | case MCE_CMD_UNKNOWN3: |
422 | case 0x0f: | 539 | case MCE_CMD_UNKNOWN5: |
423 | default: | 540 | default: |
424 | dev_info(dev, "Unknown command 0x%02x 0x%02x\n", | 541 | dev_info(dev, "Unknown command 0x%02x 0x%02x\n", |
425 | cmd, subcmd); | 542 | cmd, subcmd); |
@@ -429,6 +546,12 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, | |||
429 | default: | 546 | default: |
430 | break; | 547 | break; |
431 | } | 548 | } |
549 | |||
550 | if (cmd == MCE_IRDATA_TRAILER) | ||
551 | dev_info(dev, "End of raw IR data\n"); | ||
552 | else if ((cmd != MCE_COMMAND_HEADER) && | ||
553 | ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA)) | ||
554 | dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem); | ||
432 | } | 555 | } |
433 | 556 | ||
434 | static void mce_async_callback(struct urb *urb, struct pt_regs *regs) | 557 | static void mce_async_callback(struct urb *urb, struct pt_regs *regs) |
@@ -446,9 +569,7 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs) | |||
446 | dev_dbg(ir->dev, "callback called (status=%d len=%d)\n", | 569 | dev_dbg(ir->dev, "callback called (status=%d len=%d)\n", |
447 | urb->status, len); | 570 | urb->status, len); |
448 | 571 | ||
449 | if (debug) | 572 | mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true); |
450 | mceusb_dev_printdata(ir, urb->transfer_buffer, | ||
451 | len, true); | ||
452 | } | 573 | } |
453 | 574 | ||
454 | } | 575 | } |
@@ -536,8 +657,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) | |||
536 | return -ENOMEM; | 657 | return -ENOMEM; |
537 | 658 | ||
538 | /* MCE tx init header */ | 659 | /* MCE tx init header */ |
539 | cmdbuf[cmdcount++] = MCE_CONTROL_HEADER; | 660 | cmdbuf[cmdcount++] = MCE_COMMAND_HEADER; |
540 | cmdbuf[cmdcount++] = 0x08; | 661 | cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK; |
541 | cmdbuf[cmdcount++] = ir->tx_mask; | 662 | cmdbuf[cmdcount++] = ir->tx_mask; |
542 | 663 | ||
543 | /* Generate mce packet data */ | 664 | /* Generate mce packet data */ |
@@ -551,7 +672,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) | |||
551 | if ((cmdcount < MCE_CMDBUF_SIZE) && | 672 | if ((cmdcount < MCE_CMDBUF_SIZE) && |
552 | (cmdcount - MCE_TX_HEADER_LENGTH) % | 673 | (cmdcount - MCE_TX_HEADER_LENGTH) % |
553 | MCE_CODE_LENGTH == 0) | 674 | MCE_CODE_LENGTH == 0) |
554 | cmdbuf[cmdcount++] = MCE_PACKET_HEADER; | 675 | cmdbuf[cmdcount++] = MCE_IRDATA_HEADER; |
555 | 676 | ||
556 | /* Insert mce packet data */ | 677 | /* Insert mce packet data */ |
557 | if (cmdcount < MCE_CMDBUF_SIZE) | 678 | if (cmdcount < MCE_CMDBUF_SIZE) |
@@ -570,7 +691,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) | |||
570 | 691 | ||
571 | /* Fix packet length in last header */ | 692 | /* Fix packet length in last header */ |
572 | cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = | 693 | cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] = |
573 | 0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1; | 694 | MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) % |
695 | MCE_CODE_LENGTH - 1; | ||
574 | 696 | ||
575 | /* Check if we have room for the empty packet at the end */ | 697 | /* Check if we have room for the empty packet at the end */ |
576 | if (cmdcount >= MCE_CMDBUF_SIZE) { | 698 | if (cmdcount >= MCE_CMDBUF_SIZE) { |
@@ -579,7 +701,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n) | |||
579 | } | 701 | } |
580 | 702 | ||
581 | /* All mce commands end with an empty packet (0x80) */ | 703 | /* All mce commands end with an empty packet (0x80) */ |
582 | cmdbuf[cmdcount++] = 0x80; | 704 | cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER; |
583 | 705 | ||
584 | /* Transmit the command to the mce device */ | 706 | /* Transmit the command to the mce device */ |
585 | mce_async_out(ir, cmdbuf, cmdcount); | 707 | mce_async_out(ir, cmdbuf, cmdcount); |
@@ -608,7 +730,8 @@ static int mceusb_set_tx_mask(void *priv, u32 mask) | |||
608 | struct mceusb_dev *ir = priv; | 730 | struct mceusb_dev *ir = priv; |
609 | 731 | ||
610 | if (ir->flags.tx_mask_inverted) | 732 | if (ir->flags.tx_mask_inverted) |
611 | ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1; | 733 | ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ? |
734 | mask ^ MCE_DEFAULT_TX_MASK : mask) << 1; | ||
612 | else | 735 | else |
613 | ir->tx_mask = mask; | 736 | ir->tx_mask = mask; |
614 | 737 | ||
@@ -621,7 +744,8 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) | |||
621 | struct mceusb_dev *ir = priv; | 744 | struct mceusb_dev *ir = priv; |
622 | int clk = 10000000; | 745 | int clk = 10000000; |
623 | int prescaler = 0, divisor = 0; | 746 | int prescaler = 0, divisor = 0; |
624 | unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 }; | 747 | unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER, |
748 | MCE_CMD_S_CARRIER, 0x00, 0x00 }; | ||
625 | 749 | ||
626 | /* Carrier has changed */ | 750 | /* Carrier has changed */ |
627 | if (ir->carrier != carrier) { | 751 | if (ir->carrier != carrier) { |
@@ -629,7 +753,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) | |||
629 | if (carrier == 0) { | 753 | if (carrier == 0) { |
630 | ir->carrier = carrier; | 754 | ir->carrier = carrier; |
631 | cmdbuf[2] = 0x01; | 755 | cmdbuf[2] = 0x01; |
632 | cmdbuf[3] = 0x80; | 756 | cmdbuf[3] = MCE_IRDATA_TRAILER; |
633 | dev_dbg(ir->dev, "%s: disabling carrier " | 757 | dev_dbg(ir->dev, "%s: disabling carrier " |
634 | "modulation\n", __func__); | 758 | "modulation\n", __func__); |
635 | mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); | 759 | mce_async_out(ir, cmdbuf, sizeof(cmdbuf)); |
@@ -638,7 +762,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) | |||
638 | 762 | ||
639 | for (prescaler = 0; prescaler < 4; ++prescaler) { | 763 | for (prescaler = 0; prescaler < 4; ++prescaler) { |
640 | divisor = (clk >> (2 * prescaler)) / carrier; | 764 | divisor = (clk >> (2 * prescaler)) / carrier; |
641 | if (divisor <= 0xFF) { | 765 | if (divisor <= 0xff) { |
642 | ir->carrier = carrier; | 766 | ir->carrier = carrier; |
643 | cmdbuf[2] = prescaler; | 767 | cmdbuf[2] = prescaler; |
644 | cmdbuf[3] = divisor; | 768 | cmdbuf[3] = divisor; |
@@ -660,47 +784,36 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier) | |||
660 | 784 | ||
661 | static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) | 785 | static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) |
662 | { | 786 | { |
663 | struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; | 787 | DEFINE_IR_RAW_EVENT(rawir); |
664 | int i, start_index = 0; | 788 | int i = 0; |
665 | u8 hdr = MCE_CONTROL_HEADER; | ||
666 | 789 | ||
667 | /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ | 790 | /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ |
668 | if (ir->flags.microsoft_gen1) | 791 | if (ir->flags.microsoft_gen1) |
669 | start_index = 2; | 792 | i = 2; |
670 | 793 | ||
671 | for (i = start_index; i < buf_len;) { | 794 | for (; i < buf_len; i++) { |
672 | if (ir->rem == 0) { | 795 | switch (ir->parser_state) { |
673 | /* decode mce packets of the form (84),AA,BB,CC,DD */ | 796 | case SUBCMD: |
674 | /* IR data packets can span USB messages - rem */ | 797 | ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]); |
675 | hdr = ir->buf_in[i]; | 798 | mceusb_dev_printdata(ir, ir->buf_in, i - 1, |
676 | ir->rem = (hdr & MCE_PACKET_LENGTH_MASK); | 799 | ir->rem + 2, false); |
677 | ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK); | 800 | ir->parser_state = CMD_DATA; |
678 | dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n", | 801 | break; |
679 | ir->rem, ir->cmd); | 802 | case PARSE_IRDATA: |
680 | i++; | ||
681 | } | ||
682 | |||
683 | /* don't process MCE commands */ | ||
684 | if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) { | ||
685 | ir->rem = 0; | ||
686 | return; | ||
687 | } | ||
688 | |||
689 | for (; (ir->rem > 0) && (i < buf_len); i++) { | ||
690 | ir->rem--; | 803 | ir->rem--; |
691 | |||
692 | rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); | 804 | rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); |
693 | rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) | 805 | rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK) |
694 | * MCE_TIME_UNIT * 1000; | 806 | * MCE_TIME_UNIT * 1000; |
695 | 807 | ||
696 | if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) { | 808 | if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) { |
697 | if (ir->rawir.pulse == rawir.pulse) | 809 | if (ir->rawir.pulse == rawir.pulse) { |
698 | ir->rawir.duration += rawir.duration; | 810 | ir->rawir.duration += rawir.duration; |
699 | else { | 811 | } else { |
700 | ir->rawir.duration = rawir.duration; | 812 | ir->rawir.duration = rawir.duration; |
701 | ir->rawir.pulse = rawir.pulse; | 813 | ir->rawir.pulse = rawir.pulse; |
702 | } | 814 | } |
703 | continue; | 815 | if (ir->rem) |
816 | break; | ||
704 | } | 817 | } |
705 | rawir.duration += ir->rawir.duration; | 818 | rawir.duration += ir->rawir.duration; |
706 | ir->rawir.duration = 0; | 819 | ir->rawir.duration = 0; |
@@ -711,14 +824,40 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) | |||
711 | rawir.duration); | 824 | rawir.duration); |
712 | 825 | ||
713 | ir_raw_event_store(ir->idev, &rawir); | 826 | ir_raw_event_store(ir->idev, &rawir); |
827 | break; | ||
828 | case CMD_DATA: | ||
829 | ir->rem--; | ||
830 | break; | ||
831 | case CMD_HEADER: | ||
832 | /* decode mce packets of the form (84),AA,BB,CC,DD */ | ||
833 | /* IR data packets can span USB messages - rem */ | ||
834 | ir->cmd = ir->buf_in[i]; | ||
835 | if ((ir->cmd == MCE_COMMAND_HEADER) || | ||
836 | ((ir->cmd & MCE_COMMAND_MASK) != | ||
837 | MCE_COMMAND_IRDATA)) { | ||
838 | ir->parser_state = SUBCMD; | ||
839 | continue; | ||
840 | } | ||
841 | ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); | ||
842 | mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false); | ||
843 | if (ir->rem) { | ||
844 | ir->parser_state = PARSE_IRDATA; | ||
845 | break; | ||
846 | } | ||
847 | /* | ||
848 | * a package with len=0 (e. g. 0x80) means end of | ||
849 | * data. We could use it to do the call to | ||
850 | * ir_raw_event_handle(). For now, we don't need to | ||
851 | * use it. | ||
852 | */ | ||
853 | break; | ||
714 | } | 854 | } |
715 | 855 | ||
716 | if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f) | 856 | if (ir->parser_state != CMD_HEADER && !ir->rem) |
717 | ir->rem = 0; | 857 | ir->parser_state = CMD_HEADER; |
718 | |||
719 | dev_dbg(ir->dev, "calling ir_raw_event_handle\n"); | ||
720 | ir_raw_event_handle(ir->idev); | ||
721 | } | 858 | } |
859 | dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n"); | ||
860 | ir_raw_event_handle(ir->idev); | ||
722 | } | 861 | } |
723 | 862 | ||
724 | static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) | 863 | static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) |
@@ -737,9 +876,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) | |||
737 | 876 | ||
738 | buf_len = urb->actual_length; | 877 | buf_len = urb->actual_length; |
739 | 878 | ||
740 | if (debug) | ||
741 | mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false); | ||
742 | |||
743 | if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { | 879 | if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { |
744 | ir->send_flags = SEND_FLAG_COMPLETE; | 880 | ir->send_flags = SEND_FLAG_COMPLETE; |
745 | dev_dbg(ir->dev, "setup answer received %d bytes\n", | 881 | dev_dbg(ir->dev, "setup answer received %d bytes\n", |
@@ -760,6 +896,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs) | |||
760 | 896 | ||
761 | case -EPIPE: | 897 | case -EPIPE: |
762 | default: | 898 | default: |
899 | dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status); | ||
763 | break; | 900 | break; |
764 | } | 901 | } |
765 | 902 | ||
@@ -865,6 +1002,8 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) | |||
865 | struct input_dev *idev; | 1002 | struct input_dev *idev; |
866 | struct ir_dev_props *props; | 1003 | struct ir_dev_props *props; |
867 | struct device *dev = ir->dev; | 1004 | struct device *dev = ir->dev; |
1005 | const char *rc_map = RC_MAP_RC6_MCE; | ||
1006 | const char *name = "Media Center Ed. eHome Infrared Remote Transceiver"; | ||
868 | int ret = -ENODEV; | 1007 | int ret = -ENODEV; |
869 | 1008 | ||
870 | idev = input_allocate_device(); | 1009 | idev = input_allocate_device(); |
@@ -880,8 +1019,11 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) | |||
880 | goto props_alloc_failed; | 1019 | goto props_alloc_failed; |
881 | } | 1020 | } |
882 | 1021 | ||
883 | snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome " | 1022 | if (mceusb_model[ir->model].name) |
884 | "Infrared Remote Transceiver (%04x:%04x)", | 1023 | name = mceusb_model[ir->model].name; |
1024 | |||
1025 | snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)", | ||
1026 | name, | ||
885 | le16_to_cpu(ir->usbdev->descriptor.idVendor), | 1027 | le16_to_cpu(ir->usbdev->descriptor.idVendor), |
886 | le16_to_cpu(ir->usbdev->descriptor.idProduct)); | 1028 | le16_to_cpu(ir->usbdev->descriptor.idProduct)); |
887 | 1029 | ||
@@ -899,7 +1041,10 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir) | |||
899 | 1041 | ||
900 | ir->props = props; | 1042 | ir->props = props; |
901 | 1043 | ||
902 | ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME); | 1044 | if (mceusb_model[ir->model].rc_map) |
1045 | rc_map = mceusb_model[ir->model].rc_map; | ||
1046 | |||
1047 | ret = ir_input_register(idev, rc_map, props, DRIVER_NAME); | ||
903 | if (ret < 0) { | 1048 | if (ret < 0) { |
904 | dev_err(dev, "remote input device register failed\n"); | 1049 | dev_err(dev, "remote input device register failed\n"); |
905 | goto irdev_failed; | 1050 | goto irdev_failed; |
@@ -926,17 +1071,26 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, | |||
926 | struct mceusb_dev *ir = NULL; | 1071 | struct mceusb_dev *ir = NULL; |
927 | int pipe, maxp, i; | 1072 | int pipe, maxp, i; |
928 | char buf[63], name[128] = ""; | 1073 | char buf[63], name[128] = ""; |
1074 | enum mceusb_model_type model = id->driver_info; | ||
929 | bool is_gen3; | 1075 | bool is_gen3; |
930 | bool is_microsoft_gen1; | 1076 | bool is_microsoft_gen1; |
931 | bool tx_mask_inverted; | 1077 | bool tx_mask_inverted; |
1078 | bool is_polaris; | ||
932 | 1079 | ||
933 | dev_dbg(&intf->dev, ": %s called\n", __func__); | 1080 | dev_dbg(&intf->dev, ": %s called\n", __func__); |
934 | 1081 | ||
935 | idesc = intf->cur_altsetting; | 1082 | idesc = intf->cur_altsetting; |
936 | 1083 | ||
937 | is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0; | 1084 | is_gen3 = mceusb_model[model].mce_gen3; |
938 | is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0; | 1085 | is_microsoft_gen1 = mceusb_model[model].mce_gen1; |
939 | tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1; | 1086 | tx_mask_inverted = mceusb_model[model].tx_mask_inverted; |
1087 | is_polaris = mceusb_model[model].is_polaris; | ||
1088 | |||
1089 | if (is_polaris) { | ||
1090 | /* Interface 0 is IR */ | ||
1091 | if (idesc->desc.bInterfaceNumber) | ||
1092 | return -ENODEV; | ||
1093 | } | ||
940 | 1094 | ||
941 | /* step through the endpoints to find first bulk in and out endpoint */ | 1095 | /* step through the endpoints to find first bulk in and out endpoint */ |
942 | for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { | 1096 | for (i = 0; i < idesc->desc.bNumEndpoints; ++i) { |
@@ -997,6 +1151,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf, | |||
997 | ir->len_in = maxp; | 1151 | ir->len_in = maxp; |
998 | ir->flags.microsoft_gen1 = is_microsoft_gen1; | 1152 | ir->flags.microsoft_gen1 = is_microsoft_gen1; |
999 | ir->flags.tx_mask_inverted = tx_mask_inverted; | 1153 | ir->flags.tx_mask_inverted = tx_mask_inverted; |
1154 | ir->model = model; | ||
1155 | |||
1156 | init_ir_raw_event(&ir->rawir); | ||
1000 | 1157 | ||
1001 | /* Saving usb interface data for use by the transmitter routine */ | 1158 | /* Saving usb interface data for use by the transmitter routine */ |
1002 | ir->usb_ep_in = ep_in; | 1159 | ir->usb_ep_in = ep_in; |
diff --git a/drivers/media/IR/nuvoton-cir.c b/drivers/media/IR/nuvoton-cir.c new file mode 100644 index 000000000000..301be53aee85 --- /dev/null +++ b/drivers/media/IR/nuvoton-cir.c | |||
@@ -0,0 +1,1246 @@ | |||
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 <linux/input.h> | ||
36 | #include <media/ir-core.h> | ||
37 | #include <linux/pci_ids.h> | ||
38 | |||
39 | #include "nuvoton-cir.h" | ||
40 | |||
41 | static char *chip_id = "w836x7hg"; | ||
42 | |||
43 | /* write val to config reg */ | ||
44 | static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg) | ||
45 | { | ||
46 | outb(reg, nvt->cr_efir); | ||
47 | outb(val, nvt->cr_efdr); | ||
48 | } | ||
49 | |||
50 | /* read val from config reg */ | ||
51 | static inline u8 nvt_cr_read(struct nvt_dev *nvt, u8 reg) | ||
52 | { | ||
53 | outb(reg, nvt->cr_efir); | ||
54 | return inb(nvt->cr_efdr); | ||
55 | } | ||
56 | |||
57 | /* update config register bit without changing other bits */ | ||
58 | static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) | ||
59 | { | ||
60 | u8 tmp = nvt_cr_read(nvt, reg) | val; | ||
61 | nvt_cr_write(nvt, tmp, reg); | ||
62 | } | ||
63 | |||
64 | /* clear config register bit without changing other bits */ | ||
65 | static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg) | ||
66 | { | ||
67 | u8 tmp = nvt_cr_read(nvt, reg) & ~val; | ||
68 | nvt_cr_write(nvt, tmp, reg); | ||
69 | } | ||
70 | |||
71 | /* enter extended function mode */ | ||
72 | static inline void nvt_efm_enable(struct nvt_dev *nvt) | ||
73 | { | ||
74 | /* Enabling Extended Function Mode explicitly requires writing 2x */ | ||
75 | outb(EFER_EFM_ENABLE, nvt->cr_efir); | ||
76 | outb(EFER_EFM_ENABLE, nvt->cr_efir); | ||
77 | } | ||
78 | |||
79 | /* exit extended function mode */ | ||
80 | static inline void nvt_efm_disable(struct nvt_dev *nvt) | ||
81 | { | ||
82 | outb(EFER_EFM_DISABLE, nvt->cr_efir); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * When you want to address a specific logical device, write its logical | ||
87 | * device number to CR_LOGICAL_DEV_SEL, then enable/disable by writing | ||
88 | * 0x1/0x0 respectively to CR_LOGICAL_DEV_EN. | ||
89 | */ | ||
90 | static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev) | ||
91 | { | ||
92 | outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir); | ||
93 | outb(ldev, nvt->cr_efdr); | ||
94 | } | ||
95 | |||
96 | /* write val to cir config register */ | ||
97 | static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset) | ||
98 | { | ||
99 | outb(val, nvt->cir_addr + offset); | ||
100 | } | ||
101 | |||
102 | /* read val from cir config register */ | ||
103 | static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset) | ||
104 | { | ||
105 | u8 val; | ||
106 | |||
107 | val = inb(nvt->cir_addr + offset); | ||
108 | |||
109 | return val; | ||
110 | } | ||
111 | |||
112 | /* write val to cir wake register */ | ||
113 | static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt, | ||
114 | u8 val, u8 offset) | ||
115 | { | ||
116 | outb(val, nvt->cir_wake_addr + offset); | ||
117 | } | ||
118 | |||
119 | /* read val from cir wake config register */ | ||
120 | static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset) | ||
121 | { | ||
122 | u8 val; | ||
123 | |||
124 | val = inb(nvt->cir_wake_addr + offset); | ||
125 | |||
126 | return val; | ||
127 | } | ||
128 | |||
129 | #define pr_reg(text, ...) \ | ||
130 | printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__) | ||
131 | |||
132 | /* dump current cir register contents */ | ||
133 | static void cir_dump_regs(struct nvt_dev *nvt) | ||
134 | { | ||
135 | nvt_efm_enable(nvt); | ||
136 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); | ||
137 | |||
138 | pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME); | ||
139 | pr_reg(" * CR CIR ACTIVE : 0x%x\n", | ||
140 | nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); | ||
141 | pr_reg(" * CR CIR BASE ADDR: 0x%x\n", | ||
142 | (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | | ||
143 | nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); | ||
144 | pr_reg(" * CR CIR IRQ NUM: 0x%x\n", | ||
145 | nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); | ||
146 | |||
147 | nvt_efm_disable(nvt); | ||
148 | |||
149 | pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME); | ||
150 | pr_reg(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON)); | ||
151 | pr_reg(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS)); | ||
152 | pr_reg(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN)); | ||
153 | pr_reg(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT)); | ||
154 | pr_reg(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP)); | ||
155 | pr_reg(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC)); | ||
156 | pr_reg(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH)); | ||
157 | pr_reg(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL)); | ||
158 | pr_reg(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON)); | ||
159 | pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS)); | ||
160 | pr_reg(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO)); | ||
161 | pr_reg(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT)); | ||
162 | pr_reg(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO)); | ||
163 | pr_reg(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH)); | ||
164 | pr_reg(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL)); | ||
165 | pr_reg(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM)); | ||
166 | } | ||
167 | |||
168 | /* dump current cir wake register contents */ | ||
169 | static void cir_wake_dump_regs(struct nvt_dev *nvt) | ||
170 | { | ||
171 | u8 i, fifo_len; | ||
172 | |||
173 | nvt_efm_enable(nvt); | ||
174 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); | ||
175 | |||
176 | pr_reg("%s: Dump CIR WAKE logical device registers:\n", | ||
177 | NVT_DRIVER_NAME); | ||
178 | pr_reg(" * CR CIR WAKE ACTIVE : 0x%x\n", | ||
179 | nvt_cr_read(nvt, CR_LOGICAL_DEV_EN)); | ||
180 | pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n", | ||
181 | (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) | | ||
182 | nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO)); | ||
183 | pr_reg(" * CR CIR WAKE IRQ NUM: 0x%x\n", | ||
184 | nvt_cr_read(nvt, CR_CIR_IRQ_RSRC)); | ||
185 | |||
186 | nvt_efm_disable(nvt); | ||
187 | |||
188 | pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME); | ||
189 | pr_reg(" * IRCON: 0x%x\n", | ||
190 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON)); | ||
191 | pr_reg(" * IRSTS: 0x%x\n", | ||
192 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS)); | ||
193 | pr_reg(" * IREN: 0x%x\n", | ||
194 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN)); | ||
195 | pr_reg(" * FIFO CMP DEEP: 0x%x\n", | ||
196 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP)); | ||
197 | pr_reg(" * FIFO CMP TOL: 0x%x\n", | ||
198 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL)); | ||
199 | pr_reg(" * FIFO COUNT: 0x%x\n", | ||
200 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT)); | ||
201 | pr_reg(" * SLCH: 0x%x\n", | ||
202 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH)); | ||
203 | pr_reg(" * SLCL: 0x%x\n", | ||
204 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL)); | ||
205 | pr_reg(" * FIFOCON: 0x%x\n", | ||
206 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON)); | ||
207 | pr_reg(" * SRXFSTS: 0x%x\n", | ||
208 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS)); | ||
209 | pr_reg(" * SAMPLE RX FIFO: 0x%x\n", | ||
210 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO)); | ||
211 | pr_reg(" * WR FIFO DATA: 0x%x\n", | ||
212 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA)); | ||
213 | pr_reg(" * RD FIFO ONLY: 0x%x\n", | ||
214 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); | ||
215 | pr_reg(" * RD FIFO ONLY IDX: 0x%x\n", | ||
216 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)); | ||
217 | pr_reg(" * FIFO IGNORE: 0x%x\n", | ||
218 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE)); | ||
219 | pr_reg(" * IRFSM: 0x%x\n", | ||
220 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM)); | ||
221 | |||
222 | fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); | ||
223 | pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len); | ||
224 | pr_reg("* Contents = "); | ||
225 | for (i = 0; i < fifo_len; i++) | ||
226 | printk(KERN_CONT "%02x ", | ||
227 | nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY)); | ||
228 | printk(KERN_CONT "\n"); | ||
229 | } | ||
230 | |||
231 | /* detect hardware features */ | ||
232 | static int nvt_hw_detect(struct nvt_dev *nvt) | ||
233 | { | ||
234 | unsigned long flags; | ||
235 | u8 chip_major, chip_minor; | ||
236 | int ret = 0; | ||
237 | |||
238 | nvt_efm_enable(nvt); | ||
239 | |||
240 | /* Check if we're wired for the alternate EFER setup */ | ||
241 | chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); | ||
242 | if (chip_major == 0xff) { | ||
243 | nvt->cr_efir = CR_EFIR2; | ||
244 | nvt->cr_efdr = CR_EFDR2; | ||
245 | nvt_efm_enable(nvt); | ||
246 | chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI); | ||
247 | } | ||
248 | |||
249 | chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO); | ||
250 | nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor); | ||
251 | |||
252 | if (chip_major != CHIP_ID_HIGH && | ||
253 | (chip_minor != CHIP_ID_LOW || chip_minor != CHIP_ID_LOW2)) | ||
254 | ret = -ENODEV; | ||
255 | |||
256 | nvt_efm_disable(nvt); | ||
257 | |||
258 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
259 | nvt->chip_major = chip_major; | ||
260 | nvt->chip_minor = chip_minor; | ||
261 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
262 | |||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static void nvt_cir_ldev_init(struct nvt_dev *nvt) | ||
267 | { | ||
268 | u8 val; | ||
269 | |||
270 | /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */ | ||
271 | val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL); | ||
272 | val &= OUTPUT_PIN_SEL_MASK; | ||
273 | val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB); | ||
274 | nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL); | ||
275 | |||
276 | /* Select CIR logical device and enable */ | ||
277 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); | ||
278 | nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); | ||
279 | |||
280 | nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI); | ||
281 | nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO); | ||
282 | |||
283 | nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC); | ||
284 | |||
285 | nvt_dbg("CIR initialized, base io port address: 0x%lx, irq: %d", | ||
286 | nvt->cir_addr, nvt->cir_irq); | ||
287 | } | ||
288 | |||
289 | static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt) | ||
290 | { | ||
291 | /* Select ACPI logical device, enable it and CIR Wake */ | ||
292 | nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); | ||
293 | nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); | ||
294 | |||
295 | /* Enable CIR Wake via PSOUT# (Pin60) */ | ||
296 | nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); | ||
297 | |||
298 | /* enable cir interrupt of mouse/keyboard IRQ event */ | ||
299 | nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); | ||
300 | |||
301 | /* enable pme interrupt of cir wakeup event */ | ||
302 | nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); | ||
303 | |||
304 | /* Select CIR Wake logical device and enable */ | ||
305 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); | ||
306 | nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); | ||
307 | |||
308 | nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI); | ||
309 | nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO); | ||
310 | |||
311 | nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC); | ||
312 | |||
313 | nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d", | ||
314 | nvt->cir_wake_addr, nvt->cir_wake_irq); | ||
315 | } | ||
316 | |||
317 | /* clear out the hardware's cir rx fifo */ | ||
318 | static void nvt_clear_cir_fifo(struct nvt_dev *nvt) | ||
319 | { | ||
320 | u8 val; | ||
321 | |||
322 | val = nvt_cir_reg_read(nvt, CIR_FIFOCON); | ||
323 | nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); | ||
324 | } | ||
325 | |||
326 | /* clear out the hardware's cir wake rx fifo */ | ||
327 | static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt) | ||
328 | { | ||
329 | u8 val; | ||
330 | |||
331 | val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON); | ||
332 | nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR, | ||
333 | CIR_WAKE_FIFOCON); | ||
334 | } | ||
335 | |||
336 | /* clear out the hardware's cir tx fifo */ | ||
337 | static void nvt_clear_tx_fifo(struct nvt_dev *nvt) | ||
338 | { | ||
339 | u8 val; | ||
340 | |||
341 | val = nvt_cir_reg_read(nvt, CIR_FIFOCON); | ||
342 | nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON); | ||
343 | } | ||
344 | |||
345 | /* enable RX Trigger Level Reach and Packet End interrupts */ | ||
346 | static void nvt_set_cir_iren(struct nvt_dev *nvt) | ||
347 | { | ||
348 | u8 iren; | ||
349 | |||
350 | iren = CIR_IREN_RTR | CIR_IREN_PE; | ||
351 | nvt_cir_reg_write(nvt, iren, CIR_IREN); | ||
352 | } | ||
353 | |||
354 | static void nvt_cir_regs_init(struct nvt_dev *nvt) | ||
355 | { | ||
356 | /* set sample limit count (PE interrupt raised when reached) */ | ||
357 | nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH); | ||
358 | nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL); | ||
359 | |||
360 | /* set fifo irq trigger levels */ | ||
361 | nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV | | ||
362 | CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON); | ||
363 | |||
364 | /* | ||
365 | * Enable TX and RX, specify carrier on = low, off = high, and set | ||
366 | * sample period (currently 50us) | ||
367 | */ | ||
368 | nvt_cir_reg_write(nvt, | ||
369 | CIR_IRCON_TXEN | CIR_IRCON_RXEN | | ||
370 | CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, | ||
371 | CIR_IRCON); | ||
372 | |||
373 | /* clear hardware rx and tx fifos */ | ||
374 | nvt_clear_cir_fifo(nvt); | ||
375 | nvt_clear_tx_fifo(nvt); | ||
376 | |||
377 | /* clear any and all stray interrupts */ | ||
378 | nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); | ||
379 | |||
380 | /* and finally, enable interrupts */ | ||
381 | nvt_set_cir_iren(nvt); | ||
382 | } | ||
383 | |||
384 | static void nvt_cir_wake_regs_init(struct nvt_dev *nvt) | ||
385 | { | ||
386 | /* set number of bytes needed for wake key comparison (default 67) */ | ||
387 | nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_LEN, CIR_WAKE_FIFO_CMP_DEEP); | ||
388 | |||
389 | /* set tolerance/variance allowed per byte during wake compare */ | ||
390 | nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE, | ||
391 | CIR_WAKE_FIFO_CMP_TOL); | ||
392 | |||
393 | /* set sample limit count (PE interrupt raised when reached) */ | ||
394 | nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH); | ||
395 | nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL); | ||
396 | |||
397 | /* set cir wake fifo rx trigger level (currently 67) */ | ||
398 | nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV, | ||
399 | CIR_WAKE_FIFOCON); | ||
400 | |||
401 | /* | ||
402 | * Enable TX and RX, specific carrier on = low, off = high, and set | ||
403 | * sample period (currently 50us) | ||
404 | */ | ||
405 | nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | | ||
406 | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | | ||
407 | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, | ||
408 | CIR_WAKE_IRCON); | ||
409 | |||
410 | /* clear cir wake rx fifo */ | ||
411 | nvt_clear_cir_wake_fifo(nvt); | ||
412 | |||
413 | /* clear any and all stray interrupts */ | ||
414 | nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); | ||
415 | } | ||
416 | |||
417 | static void nvt_enable_wake(struct nvt_dev *nvt) | ||
418 | { | ||
419 | nvt_efm_enable(nvt); | ||
420 | |||
421 | nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI); | ||
422 | nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE); | ||
423 | nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS); | ||
424 | nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2); | ||
425 | |||
426 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE); | ||
427 | nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); | ||
428 | |||
429 | nvt_efm_disable(nvt); | ||
430 | |||
431 | nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | | ||
432 | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | | ||
433 | CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL, | ||
434 | CIR_WAKE_IRCON); | ||
435 | nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); | ||
436 | nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); | ||
437 | } | ||
438 | |||
439 | /* rx carrier detect only works in learning mode, must be called w/nvt_lock */ | ||
440 | static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) | ||
441 | { | ||
442 | u32 count, carrier, duration = 0; | ||
443 | int i; | ||
444 | |||
445 | count = nvt_cir_reg_read(nvt, CIR_FCCL) | | ||
446 | nvt_cir_reg_read(nvt, CIR_FCCH) << 8; | ||
447 | |||
448 | for (i = 0; i < nvt->pkts; i++) { | ||
449 | if (nvt->buf[i] & BUF_PULSE_BIT) | ||
450 | duration += nvt->buf[i] & BUF_LEN_MASK; | ||
451 | } | ||
452 | |||
453 | duration *= SAMPLE_PERIOD; | ||
454 | |||
455 | if (!count || !duration) { | ||
456 | nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)", | ||
457 | count, duration); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | carrier = (count * 1000000) / duration; | ||
462 | |||
463 | if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER)) | ||
464 | nvt_dbg("WTF? Carrier frequency out of range!"); | ||
465 | |||
466 | nvt_dbg("Carrier frequency: %u (count %u, duration %u)", | ||
467 | carrier, count, duration); | ||
468 | |||
469 | return carrier; | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * set carrier frequency | ||
474 | * | ||
475 | * set carrier on 2 registers: CP & CC | ||
476 | * always set CP as 0x81 | ||
477 | * set CC by SPEC, CC = 3MHz/carrier - 1 | ||
478 | */ | ||
479 | static int nvt_set_tx_carrier(void *data, u32 carrier) | ||
480 | { | ||
481 | struct nvt_dev *nvt = data; | ||
482 | u16 val; | ||
483 | |||
484 | nvt_cir_reg_write(nvt, 1, CIR_CP); | ||
485 | val = 3000000 / (carrier) - 1; | ||
486 | nvt_cir_reg_write(nvt, val & 0xff, CIR_CC); | ||
487 | |||
488 | nvt_dbg("cp: 0x%x cc: 0x%x\n", | ||
489 | nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC)); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | /* | ||
495 | * nvt_tx_ir | ||
496 | * | ||
497 | * 1) clean TX fifo first (handled by AP) | ||
498 | * 2) copy data from user space | ||
499 | * 3) disable RX interrupts, enable TX interrupts: TTR & TFU | ||
500 | * 4) send 9 packets to TX FIFO to open TTR | ||
501 | * in interrupt_handler: | ||
502 | * 5) send all data out | ||
503 | * go back to write(): | ||
504 | * 6) disable TX interrupts, re-enable RX interupts | ||
505 | * | ||
506 | * The key problem of this function is user space data may larger than | ||
507 | * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to | ||
508 | * buf, and keep current copied data buf num in cur_buf_num. But driver's buf | ||
509 | * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to | ||
510 | * set TXFCONT as 0xff, until buf_count less than 0xff. | ||
511 | */ | ||
512 | static int nvt_tx_ir(void *priv, int *txbuf, u32 n) | ||
513 | { | ||
514 | struct nvt_dev *nvt = priv; | ||
515 | unsigned long flags; | ||
516 | size_t cur_count; | ||
517 | unsigned int i; | ||
518 | u8 iren; | ||
519 | int ret; | ||
520 | |||
521 | spin_lock_irqsave(&nvt->tx.lock, flags); | ||
522 | |||
523 | if (n >= TX_BUF_LEN) { | ||
524 | nvt->tx.buf_count = cur_count = TX_BUF_LEN; | ||
525 | ret = TX_BUF_LEN; | ||
526 | } else { | ||
527 | nvt->tx.buf_count = cur_count = n; | ||
528 | ret = n; | ||
529 | } | ||
530 | |||
531 | memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count); | ||
532 | |||
533 | nvt->tx.cur_buf_num = 0; | ||
534 | |||
535 | /* save currently enabled interrupts */ | ||
536 | iren = nvt_cir_reg_read(nvt, CIR_IREN); | ||
537 | |||
538 | /* now disable all interrupts, save TFU & TTR */ | ||
539 | nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN); | ||
540 | |||
541 | nvt->tx.tx_state = ST_TX_REPLY; | ||
542 | |||
543 | nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 | | ||
544 | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON); | ||
545 | |||
546 | /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */ | ||
547 | for (i = 0; i < 9; i++) | ||
548 | nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO); | ||
549 | |||
550 | spin_unlock_irqrestore(&nvt->tx.lock, flags); | ||
551 | |||
552 | wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST); | ||
553 | |||
554 | spin_lock_irqsave(&nvt->tx.lock, flags); | ||
555 | nvt->tx.tx_state = ST_TX_NONE; | ||
556 | spin_unlock_irqrestore(&nvt->tx.lock, flags); | ||
557 | |||
558 | /* restore enabled interrupts to prior state */ | ||
559 | nvt_cir_reg_write(nvt, iren, CIR_IREN); | ||
560 | |||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | /* dump contents of the last rx buffer we got from the hw rx fifo */ | ||
565 | static void nvt_dump_rx_buf(struct nvt_dev *nvt) | ||
566 | { | ||
567 | int i; | ||
568 | |||
569 | printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts); | ||
570 | for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++) | ||
571 | printk(KERN_CONT "0x%02x ", nvt->buf[i]); | ||
572 | printk(KERN_CONT "\n"); | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | * Process raw data in rx driver buffer, store it in raw IR event kfifo, | ||
577 | * trigger decode when appropriate. | ||
578 | * | ||
579 | * We get IR data samples one byte at a time. If the msb is set, its a pulse, | ||
580 | * otherwise its a space. The lower 7 bits are the count of SAMPLE_PERIOD | ||
581 | * (default 50us) intervals for that pulse/space. A discrete signal is | ||
582 | * followed by a series of 0x7f packets, then either 0x7<something> or 0x80 | ||
583 | * to signal more IR coming (repeats) or end of IR, respectively. We store | ||
584 | * sample data in the raw event kfifo until we see 0x7<something> (except f) | ||
585 | * or 0x80, at which time, we trigger a decode operation. | ||
586 | */ | ||
587 | static void nvt_process_rx_ir_data(struct nvt_dev *nvt) | ||
588 | { | ||
589 | DEFINE_IR_RAW_EVENT(rawir); | ||
590 | unsigned int count; | ||
591 | u32 carrier; | ||
592 | u8 sample; | ||
593 | int i; | ||
594 | |||
595 | nvt_dbg_verbose("%s firing", __func__); | ||
596 | |||
597 | if (debug) | ||
598 | nvt_dump_rx_buf(nvt); | ||
599 | |||
600 | if (nvt->carrier_detect_enabled) | ||
601 | carrier = nvt_rx_carrier_detect(nvt); | ||
602 | |||
603 | count = nvt->pkts; | ||
604 | nvt_dbg_verbose("Processing buffer of len %d", count); | ||
605 | |||
606 | for (i = 0; i < count; i++) { | ||
607 | nvt->pkts--; | ||
608 | sample = nvt->buf[i]; | ||
609 | |||
610 | rawir.pulse = ((sample & BUF_PULSE_BIT) != 0); | ||
611 | rawir.duration = (sample & BUF_LEN_MASK) | ||
612 | * SAMPLE_PERIOD * 1000; | ||
613 | |||
614 | if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) { | ||
615 | if (nvt->rawir.pulse == rawir.pulse) | ||
616 | nvt->rawir.duration += rawir.duration; | ||
617 | else { | ||
618 | nvt->rawir.duration = rawir.duration; | ||
619 | nvt->rawir.pulse = rawir.pulse; | ||
620 | } | ||
621 | continue; | ||
622 | } | ||
623 | |||
624 | rawir.duration += nvt->rawir.duration; | ||
625 | |||
626 | init_ir_raw_event(&nvt->rawir); | ||
627 | nvt->rawir.duration = 0; | ||
628 | nvt->rawir.pulse = rawir.pulse; | ||
629 | |||
630 | if (sample == BUF_PULSE_BIT) | ||
631 | rawir.pulse = false; | ||
632 | |||
633 | if (rawir.duration) { | ||
634 | nvt_dbg("Storing %s with duration %d", | ||
635 | rawir.pulse ? "pulse" : "space", | ||
636 | rawir.duration); | ||
637 | |||
638 | ir_raw_event_store(nvt->rdev, &rawir); | ||
639 | } | ||
640 | |||
641 | /* | ||
642 | * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE | ||
643 | * indicates end of IR signal, but new data incoming. In both | ||
644 | * cases, it means we're ready to call ir_raw_event_handle | ||
645 | */ | ||
646 | if (sample == BUF_PULSE_BIT || ((sample != BUF_LEN_MASK) && | ||
647 | (sample & BUF_REPEAT_MASK) == BUF_REPEAT_BYTE)) | ||
648 | ir_raw_event_handle(nvt->rdev); | ||
649 | } | ||
650 | |||
651 | if (nvt->pkts) { | ||
652 | nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts); | ||
653 | nvt->pkts = 0; | ||
654 | } | ||
655 | |||
656 | nvt_dbg_verbose("%s done", __func__); | ||
657 | } | ||
658 | |||
659 | static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) | ||
660 | { | ||
661 | nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!"); | ||
662 | |||
663 | nvt->pkts = 0; | ||
664 | nvt_clear_cir_fifo(nvt); | ||
665 | ir_raw_event_reset(nvt->rdev); | ||
666 | } | ||
667 | |||
668 | /* copy data from hardware rx fifo into driver buffer */ | ||
669 | static void nvt_get_rx_ir_data(struct nvt_dev *nvt) | ||
670 | { | ||
671 | unsigned long flags; | ||
672 | u8 fifocount, val; | ||
673 | unsigned int b_idx; | ||
674 | bool overrun = false; | ||
675 | int i; | ||
676 | |||
677 | /* Get count of how many bytes to read from RX FIFO */ | ||
678 | fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT); | ||
679 | /* if we get 0xff, probably means the logical dev is disabled */ | ||
680 | if (fifocount == 0xff) | ||
681 | return; | ||
682 | /* watch out for a fifo overrun condition */ | ||
683 | else if (fifocount > RX_BUF_LEN) { | ||
684 | overrun = true; | ||
685 | fifocount = RX_BUF_LEN; | ||
686 | } | ||
687 | |||
688 | nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount); | ||
689 | |||
690 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
691 | |||
692 | b_idx = nvt->pkts; | ||
693 | |||
694 | /* This should never happen, but lets check anyway... */ | ||
695 | if (b_idx + fifocount > RX_BUF_LEN) { | ||
696 | nvt_process_rx_ir_data(nvt); | ||
697 | b_idx = 0; | ||
698 | } | ||
699 | |||
700 | /* Read fifocount bytes from CIR Sample RX FIFO register */ | ||
701 | for (i = 0; i < fifocount; i++) { | ||
702 | val = nvt_cir_reg_read(nvt, CIR_SRXFIFO); | ||
703 | nvt->buf[b_idx + i] = val; | ||
704 | } | ||
705 | |||
706 | nvt->pkts += fifocount; | ||
707 | nvt_dbg("%s: pkts now %d", __func__, nvt->pkts); | ||
708 | |||
709 | nvt_process_rx_ir_data(nvt); | ||
710 | |||
711 | if (overrun) | ||
712 | nvt_handle_rx_fifo_overrun(nvt); | ||
713 | |||
714 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
715 | } | ||
716 | |||
717 | static void nvt_cir_log_irqs(u8 status, u8 iren) | ||
718 | { | ||
719 | nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s", | ||
720 | status, iren, | ||
721 | status & CIR_IRSTS_RDR ? " RDR" : "", | ||
722 | status & CIR_IRSTS_RTR ? " RTR" : "", | ||
723 | status & CIR_IRSTS_PE ? " PE" : "", | ||
724 | status & CIR_IRSTS_RFO ? " RFO" : "", | ||
725 | status & CIR_IRSTS_TE ? " TE" : "", | ||
726 | status & CIR_IRSTS_TTR ? " TTR" : "", | ||
727 | status & CIR_IRSTS_TFU ? " TFU" : "", | ||
728 | status & CIR_IRSTS_GH ? " GH" : "", | ||
729 | status & ~(CIR_IRSTS_RDR | CIR_IRSTS_RTR | CIR_IRSTS_PE | | ||
730 | CIR_IRSTS_RFO | CIR_IRSTS_TE | CIR_IRSTS_TTR | | ||
731 | CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : ""); | ||
732 | } | ||
733 | |||
734 | static bool nvt_cir_tx_inactive(struct nvt_dev *nvt) | ||
735 | { | ||
736 | unsigned long flags; | ||
737 | bool tx_inactive; | ||
738 | u8 tx_state; | ||
739 | |||
740 | spin_lock_irqsave(&nvt->tx.lock, flags); | ||
741 | tx_state = nvt->tx.tx_state; | ||
742 | spin_unlock_irqrestore(&nvt->tx.lock, flags); | ||
743 | |||
744 | tx_inactive = (tx_state == ST_TX_NONE); | ||
745 | |||
746 | return tx_inactive; | ||
747 | } | ||
748 | |||
749 | /* interrupt service routine for incoming and outgoing CIR data */ | ||
750 | static irqreturn_t nvt_cir_isr(int irq, void *data) | ||
751 | { | ||
752 | struct nvt_dev *nvt = data; | ||
753 | u8 status, iren, cur_state; | ||
754 | unsigned long flags; | ||
755 | |||
756 | nvt_dbg_verbose("%s firing", __func__); | ||
757 | |||
758 | nvt_efm_enable(nvt); | ||
759 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); | ||
760 | nvt_efm_disable(nvt); | ||
761 | |||
762 | /* | ||
763 | * Get IR Status register contents. Write 1 to ack/clear | ||
764 | * | ||
765 | * bit: reg name - description | ||
766 | * 7: CIR_IRSTS_RDR - RX Data Ready | ||
767 | * 6: CIR_IRSTS_RTR - RX FIFO Trigger Level Reach | ||
768 | * 5: CIR_IRSTS_PE - Packet End | ||
769 | * 4: CIR_IRSTS_RFO - RX FIFO Overrun (RDR will also be set) | ||
770 | * 3: CIR_IRSTS_TE - TX FIFO Empty | ||
771 | * 2: CIR_IRSTS_TTR - TX FIFO Trigger Level Reach | ||
772 | * 1: CIR_IRSTS_TFU - TX FIFO Underrun | ||
773 | * 0: CIR_IRSTS_GH - Min Length Detected | ||
774 | */ | ||
775 | status = nvt_cir_reg_read(nvt, CIR_IRSTS); | ||
776 | if (!status) { | ||
777 | nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); | ||
778 | nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); | ||
779 | return IRQ_RETVAL(IRQ_NONE); | ||
780 | } | ||
781 | |||
782 | /* ack/clear all irq flags we've got */ | ||
783 | nvt_cir_reg_write(nvt, status, CIR_IRSTS); | ||
784 | nvt_cir_reg_write(nvt, 0, CIR_IRSTS); | ||
785 | |||
786 | /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */ | ||
787 | iren = nvt_cir_reg_read(nvt, CIR_IREN); | ||
788 | if (!iren) { | ||
789 | nvt_dbg_verbose("%s exiting, CIR not enabled", __func__); | ||
790 | return IRQ_RETVAL(IRQ_NONE); | ||
791 | } | ||
792 | |||
793 | if (debug) | ||
794 | nvt_cir_log_irqs(status, iren); | ||
795 | |||
796 | if (status & CIR_IRSTS_RTR) { | ||
797 | /* FIXME: add code for study/learn mode */ | ||
798 | /* We only do rx if not tx'ing */ | ||
799 | if (nvt_cir_tx_inactive(nvt)) | ||
800 | nvt_get_rx_ir_data(nvt); | ||
801 | } | ||
802 | |||
803 | if (status & CIR_IRSTS_PE) { | ||
804 | if (nvt_cir_tx_inactive(nvt)) | ||
805 | nvt_get_rx_ir_data(nvt); | ||
806 | |||
807 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
808 | |||
809 | cur_state = nvt->study_state; | ||
810 | |||
811 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
812 | |||
813 | if (cur_state == ST_STUDY_NONE) | ||
814 | nvt_clear_cir_fifo(nvt); | ||
815 | } | ||
816 | |||
817 | if (status & CIR_IRSTS_TE) | ||
818 | nvt_clear_tx_fifo(nvt); | ||
819 | |||
820 | if (status & CIR_IRSTS_TTR) { | ||
821 | unsigned int pos, count; | ||
822 | u8 tmp; | ||
823 | |||
824 | spin_lock_irqsave(&nvt->tx.lock, flags); | ||
825 | |||
826 | pos = nvt->tx.cur_buf_num; | ||
827 | count = nvt->tx.buf_count; | ||
828 | |||
829 | /* Write data into the hardware tx fifo while pos < count */ | ||
830 | if (pos < count) { | ||
831 | nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO); | ||
832 | nvt->tx.cur_buf_num++; | ||
833 | /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */ | ||
834 | } else { | ||
835 | tmp = nvt_cir_reg_read(nvt, CIR_IREN); | ||
836 | nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN); | ||
837 | } | ||
838 | |||
839 | spin_unlock_irqrestore(&nvt->tx.lock, flags); | ||
840 | |||
841 | } | ||
842 | |||
843 | if (status & CIR_IRSTS_TFU) { | ||
844 | spin_lock_irqsave(&nvt->tx.lock, flags); | ||
845 | if (nvt->tx.tx_state == ST_TX_REPLY) { | ||
846 | nvt->tx.tx_state = ST_TX_REQUEST; | ||
847 | wake_up(&nvt->tx.queue); | ||
848 | } | ||
849 | spin_unlock_irqrestore(&nvt->tx.lock, flags); | ||
850 | } | ||
851 | |||
852 | nvt_dbg_verbose("%s done", __func__); | ||
853 | return IRQ_RETVAL(IRQ_HANDLED); | ||
854 | } | ||
855 | |||
856 | /* Interrupt service routine for CIR Wake */ | ||
857 | static irqreturn_t nvt_cir_wake_isr(int irq, void *data) | ||
858 | { | ||
859 | u8 status, iren, val; | ||
860 | struct nvt_dev *nvt = data; | ||
861 | unsigned long flags; | ||
862 | |||
863 | nvt_dbg_wake("%s firing", __func__); | ||
864 | |||
865 | status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS); | ||
866 | if (!status) | ||
867 | return IRQ_RETVAL(IRQ_NONE); | ||
868 | |||
869 | if (status & CIR_WAKE_IRSTS_IR_PENDING) | ||
870 | nvt_clear_cir_wake_fifo(nvt); | ||
871 | |||
872 | nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS); | ||
873 | nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS); | ||
874 | |||
875 | /* Interrupt may be shared with CIR, bail if Wake not enabled */ | ||
876 | iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN); | ||
877 | if (!iren) { | ||
878 | nvt_dbg_wake("%s exiting, wake not enabled", __func__); | ||
879 | return IRQ_RETVAL(IRQ_HANDLED); | ||
880 | } | ||
881 | |||
882 | if ((status & CIR_WAKE_IRSTS_PE) && | ||
883 | (nvt->wake_state == ST_WAKE_START)) { | ||
884 | while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) { | ||
885 | val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); | ||
886 | nvt_dbg("setting wake up key: 0x%x", val); | ||
887 | } | ||
888 | |||
889 | nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); | ||
890 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
891 | nvt->wake_state = ST_WAKE_FINISH; | ||
892 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
893 | } | ||
894 | |||
895 | nvt_dbg_wake("%s done", __func__); | ||
896 | return IRQ_RETVAL(IRQ_HANDLED); | ||
897 | } | ||
898 | |||
899 | static void nvt_enable_cir(struct nvt_dev *nvt) | ||
900 | { | ||
901 | /* set function enable flags */ | ||
902 | nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | | ||
903 | CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL, | ||
904 | CIR_IRCON); | ||
905 | |||
906 | nvt_efm_enable(nvt); | ||
907 | |||
908 | /* enable the CIR logical device */ | ||
909 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); | ||
910 | nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); | ||
911 | |||
912 | nvt_efm_disable(nvt); | ||
913 | |||
914 | /* clear all pending interrupts */ | ||
915 | nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); | ||
916 | |||
917 | /* enable interrupts */ | ||
918 | nvt_set_cir_iren(nvt); | ||
919 | } | ||
920 | |||
921 | static void nvt_disable_cir(struct nvt_dev *nvt) | ||
922 | { | ||
923 | /* disable CIR interrupts */ | ||
924 | nvt_cir_reg_write(nvt, 0, CIR_IREN); | ||
925 | |||
926 | /* clear any and all pending interrupts */ | ||
927 | nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS); | ||
928 | |||
929 | /* clear all function enable flags */ | ||
930 | nvt_cir_reg_write(nvt, 0, CIR_IRCON); | ||
931 | |||
932 | /* clear hardware rx and tx fifos */ | ||
933 | nvt_clear_cir_fifo(nvt); | ||
934 | nvt_clear_tx_fifo(nvt); | ||
935 | |||
936 | nvt_efm_enable(nvt); | ||
937 | |||
938 | /* disable the CIR logical device */ | ||
939 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); | ||
940 | nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); | ||
941 | |||
942 | nvt_efm_disable(nvt); | ||
943 | } | ||
944 | |||
945 | static int nvt_open(void *data) | ||
946 | { | ||
947 | struct nvt_dev *nvt = (struct nvt_dev *)data; | ||
948 | unsigned long flags; | ||
949 | |||
950 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
951 | nvt->in_use = true; | ||
952 | nvt_enable_cir(nvt); | ||
953 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static void nvt_close(void *data) | ||
959 | { | ||
960 | struct nvt_dev *nvt = (struct nvt_dev *)data; | ||
961 | unsigned long flags; | ||
962 | |||
963 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
964 | nvt->in_use = false; | ||
965 | nvt_disable_cir(nvt); | ||
966 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
967 | } | ||
968 | |||
969 | /* Allocate memory, probe hardware, and initialize everything */ | ||
970 | static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) | ||
971 | { | ||
972 | struct nvt_dev *nvt = NULL; | ||
973 | struct input_dev *rdev = NULL; | ||
974 | struct ir_dev_props *props = NULL; | ||
975 | int ret = -ENOMEM; | ||
976 | |||
977 | nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL); | ||
978 | if (!nvt) | ||
979 | return ret; | ||
980 | |||
981 | props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); | ||
982 | if (!props) | ||
983 | goto failure; | ||
984 | |||
985 | /* input device for IR remote (and tx) */ | ||
986 | rdev = input_allocate_device(); | ||
987 | if (!rdev) | ||
988 | goto failure; | ||
989 | |||
990 | ret = -ENODEV; | ||
991 | /* validate pnp resources */ | ||
992 | if (!pnp_port_valid(pdev, 0) || | ||
993 | pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) { | ||
994 | dev_err(&pdev->dev, "IR PNP Port not valid!\n"); | ||
995 | goto failure; | ||
996 | } | ||
997 | |||
998 | if (!pnp_irq_valid(pdev, 0)) { | ||
999 | dev_err(&pdev->dev, "PNP IRQ not valid!\n"); | ||
1000 | goto failure; | ||
1001 | } | ||
1002 | |||
1003 | if (!pnp_port_valid(pdev, 1) || | ||
1004 | pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) { | ||
1005 | dev_err(&pdev->dev, "Wake PNP Port not valid!\n"); | ||
1006 | goto failure; | ||
1007 | } | ||
1008 | |||
1009 | nvt->cir_addr = pnp_port_start(pdev, 0); | ||
1010 | nvt->cir_irq = pnp_irq(pdev, 0); | ||
1011 | |||
1012 | nvt->cir_wake_addr = pnp_port_start(pdev, 1); | ||
1013 | /* irq is always shared between cir and cir wake */ | ||
1014 | nvt->cir_wake_irq = nvt->cir_irq; | ||
1015 | |||
1016 | nvt->cr_efir = CR_EFIR; | ||
1017 | nvt->cr_efdr = CR_EFDR; | ||
1018 | |||
1019 | spin_lock_init(&nvt->nvt_lock); | ||
1020 | spin_lock_init(&nvt->tx.lock); | ||
1021 | init_ir_raw_event(&nvt->rawir); | ||
1022 | |||
1023 | ret = -EBUSY; | ||
1024 | /* now claim resources */ | ||
1025 | if (!request_region(nvt->cir_addr, | ||
1026 | CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) | ||
1027 | goto failure; | ||
1028 | |||
1029 | if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED, | ||
1030 | NVT_DRIVER_NAME, (void *)nvt)) | ||
1031 | goto failure; | ||
1032 | |||
1033 | if (!request_region(nvt->cir_wake_addr, | ||
1034 | CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) | ||
1035 | goto failure; | ||
1036 | |||
1037 | if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED, | ||
1038 | NVT_DRIVER_NAME, (void *)nvt)) | ||
1039 | goto failure; | ||
1040 | |||
1041 | pnp_set_drvdata(pdev, nvt); | ||
1042 | nvt->pdev = pdev; | ||
1043 | |||
1044 | init_waitqueue_head(&nvt->tx.queue); | ||
1045 | |||
1046 | ret = nvt_hw_detect(nvt); | ||
1047 | if (ret) | ||
1048 | goto failure; | ||
1049 | |||
1050 | /* Initialize CIR & CIR Wake Logical Devices */ | ||
1051 | nvt_efm_enable(nvt); | ||
1052 | nvt_cir_ldev_init(nvt); | ||
1053 | nvt_cir_wake_ldev_init(nvt); | ||
1054 | nvt_efm_disable(nvt); | ||
1055 | |||
1056 | /* Initialize CIR & CIR Wake Config Registers */ | ||
1057 | nvt_cir_regs_init(nvt); | ||
1058 | nvt_cir_wake_regs_init(nvt); | ||
1059 | |||
1060 | /* Set up ir-core props */ | ||
1061 | props->priv = nvt; | ||
1062 | props->driver_type = RC_DRIVER_IR_RAW; | ||
1063 | props->allowed_protos = IR_TYPE_ALL; | ||
1064 | props->open = nvt_open; | ||
1065 | props->close = nvt_close; | ||
1066 | #if 0 | ||
1067 | props->min_timeout = XYZ; | ||
1068 | props->max_timeout = XYZ; | ||
1069 | props->timeout = XYZ; | ||
1070 | /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ | ||
1071 | props->rx_resolution = XYZ; | ||
1072 | |||
1073 | /* tx bits */ | ||
1074 | props->tx_resolution = XYZ; | ||
1075 | #endif | ||
1076 | props->tx_ir = nvt_tx_ir; | ||
1077 | props->s_tx_carrier = nvt_set_tx_carrier; | ||
1078 | |||
1079 | rdev->name = "Nuvoton w836x7hg Infrared Remote Transceiver"; | ||
1080 | rdev->id.bustype = BUS_HOST; | ||
1081 | rdev->id.vendor = PCI_VENDOR_ID_WINBOND2; | ||
1082 | rdev->id.product = nvt->chip_major; | ||
1083 | rdev->id.version = nvt->chip_minor; | ||
1084 | |||
1085 | nvt->props = props; | ||
1086 | nvt->rdev = rdev; | ||
1087 | |||
1088 | device_set_wakeup_capable(&pdev->dev, 1); | ||
1089 | device_set_wakeup_enable(&pdev->dev, 1); | ||
1090 | |||
1091 | ret = ir_input_register(rdev, RC_MAP_RC6_MCE, props, NVT_DRIVER_NAME); | ||
1092 | if (ret) | ||
1093 | goto failure; | ||
1094 | |||
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 | |||
1103 | failure: | ||
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 | input_free_device(rdev); | ||
1115 | kfree(props); | ||
1116 | kfree(nvt); | ||
1117 | |||
1118 | return ret; | ||
1119 | } | ||
1120 | |||
1121 | static void __devexit nvt_remove(struct pnp_dev *pdev) | ||
1122 | { | ||
1123 | struct nvt_dev *nvt = pnp_get_drvdata(pdev); | ||
1124 | unsigned long flags; | ||
1125 | |||
1126 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
1127 | /* disable CIR */ | ||
1128 | nvt_cir_reg_write(nvt, 0, CIR_IREN); | ||
1129 | nvt_disable_cir(nvt); | ||
1130 | /* enable CIR Wake (for IR power-on) */ | ||
1131 | nvt_enable_wake(nvt); | ||
1132 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
1133 | |||
1134 | /* free resources */ | ||
1135 | free_irq(nvt->cir_irq, nvt); | ||
1136 | free_irq(nvt->cir_wake_irq, nvt); | ||
1137 | release_region(nvt->cir_addr, CIR_IOREG_LENGTH); | ||
1138 | release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH); | ||
1139 | |||
1140 | ir_input_unregister(nvt->rdev); | ||
1141 | |||
1142 | kfree(nvt->props); | ||
1143 | kfree(nvt); | ||
1144 | } | ||
1145 | |||
1146 | static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) | ||
1147 | { | ||
1148 | struct nvt_dev *nvt = pnp_get_drvdata(pdev); | ||
1149 | unsigned long flags; | ||
1150 | |||
1151 | nvt_dbg("%s called", __func__); | ||
1152 | |||
1153 | /* zero out misc state tracking */ | ||
1154 | spin_lock_irqsave(&nvt->nvt_lock, flags); | ||
1155 | nvt->study_state = ST_STUDY_NONE; | ||
1156 | nvt->wake_state = ST_WAKE_NONE; | ||
1157 | spin_unlock_irqrestore(&nvt->nvt_lock, flags); | ||
1158 | |||
1159 | spin_lock_irqsave(&nvt->tx.lock, flags); | ||
1160 | nvt->tx.tx_state = ST_TX_NONE; | ||
1161 | spin_unlock_irqrestore(&nvt->tx.lock, flags); | ||
1162 | |||
1163 | /* disable all CIR interrupts */ | ||
1164 | nvt_cir_reg_write(nvt, 0, CIR_IREN); | ||
1165 | |||
1166 | nvt_efm_enable(nvt); | ||
1167 | |||
1168 | /* disable cir logical dev */ | ||
1169 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); | ||
1170 | nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN); | ||
1171 | |||
1172 | nvt_efm_disable(nvt); | ||
1173 | |||
1174 | /* make sure wake is enabled */ | ||
1175 | nvt_enable_wake(nvt); | ||
1176 | |||
1177 | return 0; | ||
1178 | } | ||
1179 | |||
1180 | static int nvt_resume(struct pnp_dev *pdev) | ||
1181 | { | ||
1182 | int ret = 0; | ||
1183 | struct nvt_dev *nvt = pnp_get_drvdata(pdev); | ||
1184 | |||
1185 | nvt_dbg("%s called", __func__); | ||
1186 | |||
1187 | /* open interrupt */ | ||
1188 | nvt_set_cir_iren(nvt); | ||
1189 | |||
1190 | /* Enable CIR logical device */ | ||
1191 | nvt_efm_enable(nvt); | ||
1192 | nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR); | ||
1193 | nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN); | ||
1194 | |||
1195 | nvt_efm_disable(nvt); | ||
1196 | |||
1197 | nvt_cir_regs_init(nvt); | ||
1198 | nvt_cir_wake_regs_init(nvt); | ||
1199 | |||
1200 | return ret; | ||
1201 | } | ||
1202 | |||
1203 | static void nvt_shutdown(struct pnp_dev *pdev) | ||
1204 | { | ||
1205 | struct nvt_dev *nvt = pnp_get_drvdata(pdev); | ||
1206 | nvt_enable_wake(nvt); | ||
1207 | } | ||
1208 | |||
1209 | static const struct pnp_device_id nvt_ids[] = { | ||
1210 | { "WEC0530", 0 }, /* CIR */ | ||
1211 | { "NTN0530", 0 }, /* CIR for new chip's pnp id*/ | ||
1212 | { "", 0 }, | ||
1213 | }; | ||
1214 | |||
1215 | static struct pnp_driver nvt_driver = { | ||
1216 | .name = NVT_DRIVER_NAME, | ||
1217 | .id_table = nvt_ids, | ||
1218 | .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, | ||
1219 | .probe = nvt_probe, | ||
1220 | .remove = __devexit_p(nvt_remove), | ||
1221 | .suspend = nvt_suspend, | ||
1222 | .resume = nvt_resume, | ||
1223 | .shutdown = nvt_shutdown, | ||
1224 | }; | ||
1225 | |||
1226 | int nvt_init(void) | ||
1227 | { | ||
1228 | return pnp_register_driver(&nvt_driver); | ||
1229 | } | ||
1230 | |||
1231 | void nvt_exit(void) | ||
1232 | { | ||
1233 | pnp_unregister_driver(&nvt_driver); | ||
1234 | } | ||
1235 | |||
1236 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
1237 | MODULE_PARM_DESC(debug, "Enable debugging output"); | ||
1238 | |||
1239 | MODULE_DEVICE_TABLE(pnp, nvt_ids); | ||
1240 | MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver"); | ||
1241 | |||
1242 | MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); | ||
1243 | MODULE_LICENSE("GPL"); | ||
1244 | |||
1245 | module_init(nvt_init); | ||
1246 | module_exit(nvt_exit); | ||
diff --git a/drivers/media/IR/nuvoton-cir.h b/drivers/media/IR/nuvoton-cir.h new file mode 100644 index 000000000000..62dc53017c8e --- /dev/null +++ b/drivers/media/IR/nuvoton-cir.h | |||
@@ -0,0 +1,408 @@ | |||
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 */ | ||
35 | static 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 | |||
67 | struct nvt_dev { | ||
68 | struct pnp_dev *pdev; | ||
69 | struct input_dev *rdev; | ||
70 | struct ir_dev_props *props; | ||
71 | struct ir_raw_event rawir; | ||
72 | |||
73 | spinlock_t nvt_lock; | ||
74 | bool in_use; | ||
75 | |||
76 | /* for rx */ | ||
77 | u8 buf[RX_BUF_LEN]; | ||
78 | unsigned int pkts; | ||
79 | |||
80 | struct { | ||
81 | spinlock_t lock; | ||
82 | u8 buf[TX_BUF_LEN]; | ||
83 | unsigned int buf_count; | ||
84 | unsigned int cur_buf_num; | ||
85 | wait_queue_head_t queue; | ||
86 | u8 tx_state; | ||
87 | } tx; | ||
88 | |||
89 | /* EFER Config register index/data pair */ | ||
90 | u8 cr_efir; | ||
91 | u8 cr_efdr; | ||
92 | |||
93 | /* hardware I/O settings */ | ||
94 | unsigned long cir_addr; | ||
95 | unsigned long cir_wake_addr; | ||
96 | int cir_irq; | ||
97 | int cir_wake_irq; | ||
98 | |||
99 | /* hardware id */ | ||
100 | u8 chip_major; | ||
101 | u8 chip_minor; | ||
102 | |||
103 | /* hardware features */ | ||
104 | bool hw_learning_capable; | ||
105 | bool hw_tx_capable; | ||
106 | |||
107 | /* rx settings */ | ||
108 | bool learning_enabled; | ||
109 | bool carrier_detect_enabled; | ||
110 | |||
111 | /* track cir wake state */ | ||
112 | u8 wake_state; | ||
113 | /* for study */ | ||
114 | u8 study_state; | ||
115 | /* carrier period = 1 / frequency */ | ||
116 | u32 carrier; | ||
117 | }; | ||
118 | |||
119 | /* study states */ | ||
120 | #define ST_STUDY_NONE 0x0 | ||
121 | #define ST_STUDY_START 0x1 | ||
122 | #define ST_STUDY_CARRIER 0x2 | ||
123 | #define ST_STUDY_ALL_RECV 0x4 | ||
124 | |||
125 | /* wake states */ | ||
126 | #define ST_WAKE_NONE 0x0 | ||
127 | #define ST_WAKE_START 0x1 | ||
128 | #define ST_WAKE_FINISH 0x2 | ||
129 | |||
130 | /* receive states */ | ||
131 | #define ST_RX_WAIT_7F 0x1 | ||
132 | #define ST_RX_WAIT_HEAD 0x2 | ||
133 | #define ST_RX_WAIT_SILENT_END 0x4 | ||
134 | |||
135 | /* send states */ | ||
136 | #define ST_TX_NONE 0x0 | ||
137 | #define ST_TX_REQUEST 0x2 | ||
138 | #define ST_TX_REPLY 0x4 | ||
139 | |||
140 | /* buffer packet constants */ | ||
141 | #define BUF_PULSE_BIT 0x80 | ||
142 | #define BUF_LEN_MASK 0x7f | ||
143 | #define BUF_REPEAT_BYTE 0x70 | ||
144 | #define BUF_REPEAT_MASK 0xf0 | ||
145 | |||
146 | /* CIR settings */ | ||
147 | |||
148 | /* total length of CIR and CIR WAKE */ | ||
149 | #define CIR_IOREG_LENGTH 0x0f | ||
150 | |||
151 | /* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */ | ||
152 | #define CIR_RX_LIMIT_COUNT 0x7d0 | ||
153 | |||
154 | /* CIR Regs */ | ||
155 | #define CIR_IRCON 0x00 | ||
156 | #define CIR_IRSTS 0x01 | ||
157 | #define CIR_IREN 0x02 | ||
158 | #define CIR_RXFCONT 0x03 | ||
159 | #define CIR_CP 0x04 | ||
160 | #define CIR_CC 0x05 | ||
161 | #define CIR_SLCH 0x06 | ||
162 | #define CIR_SLCL 0x07 | ||
163 | #define CIR_FIFOCON 0x08 | ||
164 | #define CIR_IRFIFOSTS 0x09 | ||
165 | #define CIR_SRXFIFO 0x0a | ||
166 | #define CIR_TXFCONT 0x0b | ||
167 | #define CIR_STXFIFO 0x0c | ||
168 | #define CIR_FCCH 0x0d | ||
169 | #define CIR_FCCL 0x0e | ||
170 | #define CIR_IRFSM 0x0f | ||
171 | |||
172 | /* CIR IRCON settings */ | ||
173 | #define CIR_IRCON_RECV 0x80 | ||
174 | #define CIR_IRCON_WIREN 0x40 | ||
175 | #define CIR_IRCON_TXEN 0x20 | ||
176 | #define CIR_IRCON_RXEN 0x10 | ||
177 | #define CIR_IRCON_WRXINV 0x08 | ||
178 | #define CIR_IRCON_RXINV 0x04 | ||
179 | |||
180 | #define CIR_IRCON_SAMPLE_PERIOD_SEL_1 0x00 | ||
181 | #define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01 | ||
182 | #define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02 | ||
183 | #define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03 | ||
184 | |||
185 | /* FIXME: make this a runtime option */ | ||
186 | /* select sample period as 50us */ | ||
187 | #define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50 | ||
188 | |||
189 | /* CIR IRSTS settings */ | ||
190 | #define CIR_IRSTS_RDR 0x80 | ||
191 | #define CIR_IRSTS_RTR 0x40 | ||
192 | #define CIR_IRSTS_PE 0x20 | ||
193 | #define CIR_IRSTS_RFO 0x10 | ||
194 | #define CIR_IRSTS_TE 0x08 | ||
195 | #define CIR_IRSTS_TTR 0x04 | ||
196 | #define CIR_IRSTS_TFU 0x02 | ||
197 | #define CIR_IRSTS_GH 0x01 | ||
198 | |||
199 | /* CIR IREN settings */ | ||
200 | #define CIR_IREN_RDR 0x80 | ||
201 | #define CIR_IREN_RTR 0x40 | ||
202 | #define CIR_IREN_PE 0x20 | ||
203 | #define CIR_IREN_RFO 0x10 | ||
204 | #define CIR_IREN_TE 0x08 | ||
205 | #define CIR_IREN_TTR 0x04 | ||
206 | #define CIR_IREN_TFU 0x02 | ||
207 | #define CIR_IREN_GH 0x01 | ||
208 | |||
209 | /* CIR FIFOCON settings */ | ||
210 | #define CIR_FIFOCON_TXFIFOCLR 0x80 | ||
211 | |||
212 | #define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00 | ||
213 | #define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10 | ||
214 | #define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20 | ||
215 | #define CIR_FIFOCON_TX_TRIGGER_LEV_8 0x30 | ||
216 | |||
217 | /* FIXME: make this a runtime option */ | ||
218 | /* select TX trigger level as 16 */ | ||
219 | #define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16 | ||
220 | |||
221 | #define CIR_FIFOCON_RXFIFOCLR 0x08 | ||
222 | |||
223 | #define CIR_FIFOCON_RX_TRIGGER_LEV_1 0x00 | ||
224 | #define CIR_FIFOCON_RX_TRIGGER_LEV_8 0x01 | ||
225 | #define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02 | ||
226 | #define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03 | ||
227 | |||
228 | /* FIXME: make this a runtime option */ | ||
229 | /* select RX trigger level as 24 */ | ||
230 | #define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_24 | ||
231 | |||
232 | /* CIR IRFIFOSTS settings */ | ||
233 | #define CIR_IRFIFOSTS_IR_PENDING 0x80 | ||
234 | #define CIR_IRFIFOSTS_RX_GS 0x40 | ||
235 | #define CIR_IRFIFOSTS_RX_FTA 0x20 | ||
236 | #define CIR_IRFIFOSTS_RX_EMPTY 0x10 | ||
237 | #define CIR_IRFIFOSTS_RX_FULL 0x08 | ||
238 | #define CIR_IRFIFOSTS_TX_FTA 0x04 | ||
239 | #define CIR_IRFIFOSTS_TX_EMPTY 0x02 | ||
240 | #define CIR_IRFIFOSTS_TX_FULL 0x01 | ||
241 | |||
242 | |||
243 | /* CIR WAKE UP Regs */ | ||
244 | #define CIR_WAKE_IRCON 0x00 | ||
245 | #define CIR_WAKE_IRSTS 0x01 | ||
246 | #define CIR_WAKE_IREN 0x02 | ||
247 | #define CIR_WAKE_FIFO_CMP_DEEP 0x03 | ||
248 | #define CIR_WAKE_FIFO_CMP_TOL 0x04 | ||
249 | #define CIR_WAKE_FIFO_COUNT 0x05 | ||
250 | #define CIR_WAKE_SLCH 0x06 | ||
251 | #define CIR_WAKE_SLCL 0x07 | ||
252 | #define CIR_WAKE_FIFOCON 0x08 | ||
253 | #define CIR_WAKE_SRXFSTS 0x09 | ||
254 | #define CIR_WAKE_SAMPLE_RX_FIFO 0x0a | ||
255 | #define CIR_WAKE_WR_FIFO_DATA 0x0b | ||
256 | #define CIR_WAKE_RD_FIFO_ONLY 0x0c | ||
257 | #define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0d | ||
258 | #define CIR_WAKE_FIFO_IGNORE 0x0e | ||
259 | #define CIR_WAKE_IRFSM 0x0f | ||
260 | |||
261 | /* CIR WAKE UP IRCON settings */ | ||
262 | #define CIR_WAKE_IRCON_DEC_RST 0x80 | ||
263 | #define CIR_WAKE_IRCON_MODE1 0x40 | ||
264 | #define CIR_WAKE_IRCON_MODE0 0x20 | ||
265 | #define CIR_WAKE_IRCON_RXEN 0x10 | ||
266 | #define CIR_WAKE_IRCON_R 0x08 | ||
267 | #define CIR_WAKE_IRCON_RXINV 0x04 | ||
268 | |||
269 | /* FIXME/jarod: make this a runtime option */ | ||
270 | /* select a same sample period like cir register */ | ||
271 | #define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50 | ||
272 | |||
273 | /* CIR WAKE IRSTS Bits */ | ||
274 | #define CIR_WAKE_IRSTS_RDR 0x80 | ||
275 | #define CIR_WAKE_IRSTS_RTR 0x40 | ||
276 | #define CIR_WAKE_IRSTS_PE 0x20 | ||
277 | #define CIR_WAKE_IRSTS_RFO 0x10 | ||
278 | #define CIR_WAKE_IRSTS_GH 0x08 | ||
279 | #define CIR_WAKE_IRSTS_IR_PENDING 0x01 | ||
280 | |||
281 | /* CIR WAKE UP IREN Bits */ | ||
282 | #define CIR_WAKE_IREN_RDR 0x80 | ||
283 | #define CIR_WAKE_IREN_RTR 0x40 | ||
284 | #define CIR_WAKE_IREN_PE 0x20 | ||
285 | #define CIR_WAKE_IREN_RFO 0x10 | ||
286 | #define CIR_WAKE_IREN_TE 0x08 | ||
287 | #define CIR_WAKE_IREN_TTR 0x04 | ||
288 | #define CIR_WAKE_IREN_TFU 0x02 | ||
289 | #define CIR_WAKE_IREN_GH 0x01 | ||
290 | |||
291 | /* CIR WAKE FIFOCON settings */ | ||
292 | #define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08 | ||
293 | |||
294 | #define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00 | ||
295 | #define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01 | ||
296 | #define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02 | ||
297 | #define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03 | ||
298 | |||
299 | /* FIXME: make this a runtime option */ | ||
300 | /* select WAKE UP RX trigger level as 67 */ | ||
301 | #define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 | ||
302 | |||
303 | /* CIR WAKE SRXFSTS settings */ | ||
304 | #define CIR_WAKE_IRFIFOSTS_RX_GS 0x80 | ||
305 | #define CIR_WAKE_IRFIFOSTS_RX_FTA 0x40 | ||
306 | #define CIR_WAKE_IRFIFOSTS_RX_EMPTY 0x20 | ||
307 | #define CIR_WAKE_IRFIFOSTS_RX_FULL 0x10 | ||
308 | |||
309 | /* CIR Wake FIFO buffer is 67 bytes long */ | ||
310 | #define CIR_WAKE_FIFO_LEN 67 | ||
311 | /* CIR Wake byte comparison tolerance */ | ||
312 | #define CIR_WAKE_CMP_TOLERANCE 5 | ||
313 | |||
314 | /* | ||
315 | * Extended Function Enable Registers: | ||
316 | * Extended Function Index Register | ||
317 | * Extended Function Data Register | ||
318 | */ | ||
319 | #define CR_EFIR 0x2e | ||
320 | #define CR_EFDR 0x2f | ||
321 | |||
322 | /* Possible alternate EFER values, depends on how the chip is wired */ | ||
323 | #define CR_EFIR2 0x4e | ||
324 | #define CR_EFDR2 0x4f | ||
325 | |||
326 | /* Extended Function Mode enable/disable magic values */ | ||
327 | #define EFER_EFM_ENABLE 0x87 | ||
328 | #define EFER_EFM_DISABLE 0xaa | ||
329 | |||
330 | /* Chip IDs found in CR_CHIP_ID_{HI,LO} */ | ||
331 | #define CHIP_ID_HIGH 0xb4 | ||
332 | #define CHIP_ID_LOW 0x72 | ||
333 | #define CHIP_ID_LOW2 0x73 | ||
334 | |||
335 | /* Config regs we need to care about */ | ||
336 | #define CR_SOFTWARE_RESET 0x02 | ||
337 | #define CR_LOGICAL_DEV_SEL 0x07 | ||
338 | #define CR_CHIP_ID_HI 0x20 | ||
339 | #define CR_CHIP_ID_LO 0x21 | ||
340 | #define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */ | ||
341 | #define CR_OUTPUT_PIN_SEL 0x27 | ||
342 | #define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */ | ||
343 | /* next three regs valid for both the CIR and CIR_WAKE logical devices */ | ||
344 | #define CR_CIR_BASE_ADDR_HI 0x60 | ||
345 | #define CR_CIR_BASE_ADDR_LO 0x61 | ||
346 | #define CR_CIR_IRQ_RSRC 0x70 | ||
347 | /* next three regs valid only for ACPI logical dev */ | ||
348 | #define CR_ACPI_CIR_WAKE 0xe0 | ||
349 | #define CR_ACPI_IRQ_EVENTS 0xf6 | ||
350 | #define CR_ACPI_IRQ_EVENTS2 0xf7 | ||
351 | |||
352 | /* Logical devices that we need to care about */ | ||
353 | #define LOGICAL_DEV_LPT 0x01 | ||
354 | #define LOGICAL_DEV_CIR 0x06 | ||
355 | #define LOGICAL_DEV_ACPI 0x0a | ||
356 | #define LOGICAL_DEV_CIR_WAKE 0x0e | ||
357 | |||
358 | #define LOGICAL_DEV_DISABLE 0x00 | ||
359 | #define LOGICAL_DEV_ENABLE 0x01 | ||
360 | |||
361 | #define CIR_WAKE_ENABLE_BIT 0x08 | ||
362 | #define CIR_INTR_MOUSE_IRQ_BIT 0x80 | ||
363 | #define PME_INTR_CIR_PASS_BIT 0x08 | ||
364 | |||
365 | #define OUTPUT_PIN_SEL_MASK 0xbc | ||
366 | #define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */ | ||
367 | #define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */ | ||
368 | |||
369 | /* MCE CIR signal length, related on sample period */ | ||
370 | |||
371 | /* MCE CIR controller signal length: about 43ms | ||
372 | * 43ms / 50us (sample period) * 0.85 (inaccuracy) | ||
373 | */ | ||
374 | #define CONTROLLER_BUF_LEN_MIN 830 | ||
375 | |||
376 | /* MCE CIR keyboard signal length: about 26ms | ||
377 | * 26ms / 50us (sample period) * 0.85 (inaccuracy) | ||
378 | */ | ||
379 | #define KEYBOARD_BUF_LEN_MAX 650 | ||
380 | #define KEYBOARD_BUF_LEN_MIN 610 | ||
381 | |||
382 | /* MCE CIR mouse signal length: about 24ms | ||
383 | * 24ms / 50us (sample period) * 0.85 (inaccuracy) | ||
384 | */ | ||
385 | #define MOUSE_BUF_LEN_MIN 565 | ||
386 | |||
387 | #define CIR_SAMPLE_PERIOD 50 | ||
388 | #define CIR_SAMPLE_LOW_INACCURACY 0.85 | ||
389 | |||
390 | /* MAX silence time that driver will sent to lirc */ | ||
391 | #define MAX_SILENCE_TIME 60000 | ||
392 | |||
393 | #if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100 | ||
394 | #define SAMPLE_PERIOD 100 | ||
395 | |||
396 | #elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50 | ||
397 | #define SAMPLE_PERIOD 50 | ||
398 | |||
399 | #elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25 | ||
400 | #define SAMPLE_PERIOD 25 | ||
401 | |||
402 | #else | ||
403 | #define SAMPLE_PERIOD 1 | ||
404 | #endif | ||
405 | |||
406 | /* as VISTA MCE definition, valid carrier value */ | ||
407 | #define MAX_CARRIER 60000 | ||
408 | #define MIN_CARRIER 30000 | ||
diff --git a/drivers/media/IR/streamzap.c b/drivers/media/IR/streamzap.c index 058e29fd478c..548381c35bfd 100644 --- a/drivers/media/IR/streamzap.c +++ b/drivers/media/IR/streamzap.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include <linux/input.h> | 38 | #include <linux/input.h> |
39 | #include <media/ir-core.h> | 39 | #include <media/ir-core.h> |
40 | 40 | ||
41 | #define DRIVER_VERSION "1.60" | 41 | #define DRIVER_VERSION "1.61" |
42 | #define DRIVER_NAME "streamzap" | 42 | #define DRIVER_NAME "streamzap" |
43 | #define DRIVER_DESC "Streamzap Remote Control driver" | 43 | #define DRIVER_DESC "Streamzap Remote Control driver" |
44 | 44 | ||
@@ -61,14 +61,21 @@ static struct usb_device_id streamzap_table[] = { | |||
61 | 61 | ||
62 | MODULE_DEVICE_TABLE(usb, streamzap_table); | 62 | MODULE_DEVICE_TABLE(usb, streamzap_table); |
63 | 63 | ||
64 | #define STREAMZAP_PULSE_MASK 0xf0 | 64 | #define SZ_PULSE_MASK 0xf0 |
65 | #define STREAMZAP_SPACE_MASK 0x0f | 65 | #define SZ_SPACE_MASK 0x0f |
66 | #define STREAMZAP_TIMEOUT 0xff | 66 | #define SZ_TIMEOUT 0xff |
67 | #define STREAMZAP_RESOLUTION 256 | 67 | #define SZ_RESOLUTION 256 |
68 | 68 | ||
69 | /* number of samples buffered */ | 69 | /* number of samples buffered */ |
70 | #define SZ_BUF_LEN 128 | 70 | #define SZ_BUF_LEN 128 |
71 | 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() 0 | ||
77 | #endif | ||
78 | |||
72 | enum StreamzapDecoderState { | 79 | enum StreamzapDecoderState { |
73 | PulseSpace, | 80 | PulseSpace, |
74 | FullPulse, | 81 | FullPulse, |
@@ -81,7 +88,6 @@ struct streamzap_ir { | |||
81 | 88 | ||
82 | /* ir-core */ | 89 | /* ir-core */ |
83 | struct ir_dev_props *props; | 90 | struct ir_dev_props *props; |
84 | struct ir_raw_event rawir; | ||
85 | 91 | ||
86 | /* core device info */ | 92 | /* core device info */ |
87 | struct device *dev; | 93 | struct device *dev; |
@@ -98,17 +104,6 @@ struct streamzap_ir { | |||
98 | dma_addr_t dma_in; | 104 | dma_addr_t dma_in; |
99 | unsigned int buf_in_len; | 105 | unsigned int buf_in_len; |
100 | 106 | ||
101 | /* timer used to support delay buffering */ | ||
102 | struct timer_list delay_timer; | ||
103 | bool timer_running; | ||
104 | spinlock_t timer_lock; | ||
105 | struct timer_list flush_timer; | ||
106 | bool flush; | ||
107 | |||
108 | /* delay buffer */ | ||
109 | struct kfifo fifo; | ||
110 | bool fifo_initialized; | ||
111 | |||
112 | /* track what state we're in */ | 107 | /* track what state we're in */ |
113 | enum StreamzapDecoderState decoder_state; | 108 | enum StreamzapDecoderState decoder_state; |
114 | /* tracks whether we are currently receiving some signal */ | 109 | /* tracks whether we are currently receiving some signal */ |
@@ -118,7 +113,7 @@ struct streamzap_ir { | |||
118 | /* start time of signal; necessary for gap tracking */ | 113 | /* start time of signal; necessary for gap tracking */ |
119 | struct timeval signal_last; | 114 | struct timeval signal_last; |
120 | struct timeval signal_start; | 115 | struct timeval signal_start; |
121 | /* bool timeout_enabled; */ | 116 | bool timeout_enabled; |
122 | 117 | ||
123 | char name[128]; | 118 | char name[128]; |
124 | char phys[64]; | 119 | char phys[64]; |
@@ -143,122 +138,16 @@ static struct usb_driver streamzap_driver = { | |||
143 | .id_table = streamzap_table, | 138 | .id_table = streamzap_table, |
144 | }; | 139 | }; |
145 | 140 | ||
146 | static void streamzap_stop_timer(struct streamzap_ir *sz) | 141 | static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir) |
147 | { | ||
148 | unsigned long flags; | ||
149 | |||
150 | spin_lock_irqsave(&sz->timer_lock, flags); | ||
151 | if (sz->timer_running) { | ||
152 | sz->timer_running = false; | ||
153 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
154 | del_timer_sync(&sz->delay_timer); | ||
155 | } else { | ||
156 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static void streamzap_flush_timeout(unsigned long arg) | ||
161 | { | ||
162 | struct streamzap_ir *sz = (struct streamzap_ir *)arg; | ||
163 | |||
164 | dev_info(sz->dev, "%s: callback firing\n", __func__); | ||
165 | |||
166 | /* finally start accepting data */ | ||
167 | sz->flush = false; | ||
168 | } | ||
169 | |||
170 | static void streamzap_delay_timeout(unsigned long arg) | ||
171 | { | ||
172 | struct streamzap_ir *sz = (struct streamzap_ir *)arg; | ||
173 | struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; | ||
174 | unsigned long flags; | ||
175 | int len, ret; | ||
176 | static unsigned long delay; | ||
177 | bool wake = false; | ||
178 | |||
179 | /* deliver data every 10 ms */ | ||
180 | delay = msecs_to_jiffies(10); | ||
181 | |||
182 | spin_lock_irqsave(&sz->timer_lock, flags); | ||
183 | |||
184 | if (kfifo_len(&sz->fifo) > 0) { | ||
185 | ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir)); | ||
186 | if (ret != sizeof(rawir)) | ||
187 | dev_err(sz->dev, "Problem w/kfifo_out...\n"); | ||
188 | ir_raw_event_store(sz->idev, &rawir); | ||
189 | wake = true; | ||
190 | } | ||
191 | |||
192 | len = kfifo_len(&sz->fifo); | ||
193 | if (len > 0) { | ||
194 | while ((len < SZ_BUF_LEN / 2) && | ||
195 | (len < SZ_BUF_LEN * sizeof(int))) { | ||
196 | ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir)); | ||
197 | if (ret != sizeof(rawir)) | ||
198 | dev_err(sz->dev, "Problem w/kfifo_out...\n"); | ||
199 | ir_raw_event_store(sz->idev, &rawir); | ||
200 | wake = true; | ||
201 | len = kfifo_len(&sz->fifo); | ||
202 | } | ||
203 | if (sz->timer_running) | ||
204 | mod_timer(&sz->delay_timer, jiffies + delay); | ||
205 | |||
206 | } else { | ||
207 | sz->timer_running = false; | ||
208 | } | ||
209 | |||
210 | if (wake) | ||
211 | ir_raw_event_handle(sz->idev); | ||
212 | |||
213 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
214 | } | ||
215 | |||
216 | static void streamzap_flush_delay_buffer(struct streamzap_ir *sz) | ||
217 | { | 142 | { |
218 | struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; | 143 | ir_raw_event_store(sz->idev, &rawir); |
219 | bool wake = false; | ||
220 | int ret; | ||
221 | |||
222 | while (kfifo_len(&sz->fifo) > 0) { | ||
223 | ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir)); | ||
224 | if (ret != sizeof(rawir)) | ||
225 | dev_err(sz->dev, "Problem w/kfifo_out...\n"); | ||
226 | ir_raw_event_store(sz->idev, &rawir); | ||
227 | wake = true; | ||
228 | } | ||
229 | |||
230 | if (wake) | ||
231 | ir_raw_event_handle(sz->idev); | ||
232 | } | ||
233 | |||
234 | static void sz_push(struct streamzap_ir *sz) | ||
235 | { | ||
236 | struct ir_raw_event rawir = { .pulse = false, .duration = 0 }; | ||
237 | unsigned long flags; | ||
238 | int ret; | ||
239 | |||
240 | spin_lock_irqsave(&sz->timer_lock, flags); | ||
241 | if (kfifo_len(&sz->fifo) >= sizeof(int) * SZ_BUF_LEN) { | ||
242 | ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir)); | ||
243 | if (ret != sizeof(rawir)) | ||
244 | dev_err(sz->dev, "Problem w/kfifo_out...\n"); | ||
245 | ir_raw_event_store(sz->idev, &rawir); | ||
246 | } | ||
247 | |||
248 | kfifo_in(&sz->fifo, &sz->rawir, sizeof(rawir)); | ||
249 | |||
250 | if (!sz->timer_running) { | ||
251 | sz->delay_timer.expires = jiffies + (HZ / 10); | ||
252 | add_timer(&sz->delay_timer); | ||
253 | sz->timer_running = true; | ||
254 | } | ||
255 | |||
256 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
257 | } | 144 | } |
258 | 145 | ||
259 | static void sz_push_full_pulse(struct streamzap_ir *sz, | 146 | static void sz_push_full_pulse(struct streamzap_ir *sz, |
260 | unsigned char value) | 147 | unsigned char value) |
261 | { | 148 | { |
149 | DEFINE_IR_RAW_EVENT(rawir); | ||
150 | |||
262 | if (sz->idle) { | 151 | if (sz->idle) { |
263 | long deltv; | 152 | long deltv; |
264 | 153 | ||
@@ -266,57 +155,59 @@ static void sz_push_full_pulse(struct streamzap_ir *sz, | |||
266 | do_gettimeofday(&sz->signal_start); | 155 | do_gettimeofday(&sz->signal_start); |
267 | 156 | ||
268 | deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec; | 157 | deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec; |
269 | sz->rawir.pulse = false; | 158 | rawir.pulse = false; |
270 | if (deltv > 15) { | 159 | if (deltv > 15) { |
271 | /* really long time */ | 160 | /* really long time */ |
272 | sz->rawir.duration = IR_MAX_DURATION; | 161 | rawir.duration = IR_MAX_DURATION; |
273 | } else { | 162 | } else { |
274 | sz->rawir.duration = (int)(deltv * 1000000 + | 163 | rawir.duration = (int)(deltv * 1000000 + |
275 | sz->signal_start.tv_usec - | 164 | sz->signal_start.tv_usec - |
276 | sz->signal_last.tv_usec); | 165 | sz->signal_last.tv_usec); |
277 | sz->rawir.duration -= sz->sum; | 166 | rawir.duration -= sz->sum; |
278 | sz->rawir.duration *= 1000; | 167 | rawir.duration *= 1000; |
279 | sz->rawir.duration &= IR_MAX_DURATION; | 168 | rawir.duration &= IR_MAX_DURATION; |
280 | } | 169 | } |
281 | dev_dbg(sz->dev, "ls %u\n", sz->rawir.duration); | 170 | dev_dbg(sz->dev, "ls %u\n", rawir.duration); |
282 | sz_push(sz); | 171 | sz_push(sz, rawir); |
283 | 172 | ||
284 | sz->idle = 0; | 173 | sz->idle = false; |
285 | sz->sum = 0; | 174 | sz->sum = 0; |
286 | } | 175 | } |
287 | 176 | ||
288 | sz->rawir.pulse = true; | 177 | rawir.pulse = true; |
289 | sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION; | 178 | rawir.duration = ((int) value) * SZ_RESOLUTION; |
290 | sz->rawir.duration += STREAMZAP_RESOLUTION / 2; | 179 | rawir.duration += SZ_RESOLUTION / 2; |
291 | sz->sum += sz->rawir.duration; | 180 | sz->sum += rawir.duration; |
292 | sz->rawir.duration *= 1000; | 181 | rawir.duration *= 1000; |
293 | sz->rawir.duration &= IR_MAX_DURATION; | 182 | rawir.duration &= IR_MAX_DURATION; |
294 | dev_dbg(sz->dev, "p %u\n", sz->rawir.duration); | 183 | dev_dbg(sz->dev, "p %u\n", rawir.duration); |
295 | sz_push(sz); | 184 | sz_push(sz, rawir); |
296 | } | 185 | } |
297 | 186 | ||
298 | static void sz_push_half_pulse(struct streamzap_ir *sz, | 187 | static void sz_push_half_pulse(struct streamzap_ir *sz, |
299 | unsigned char value) | 188 | unsigned char value) |
300 | { | 189 | { |
301 | sz_push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK) >> 4); | 190 | sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4); |
302 | } | 191 | } |
303 | 192 | ||
304 | static void sz_push_full_space(struct streamzap_ir *sz, | 193 | static void sz_push_full_space(struct streamzap_ir *sz, |
305 | unsigned char value) | 194 | unsigned char value) |
306 | { | 195 | { |
307 | sz->rawir.pulse = false; | 196 | DEFINE_IR_RAW_EVENT(rawir); |
308 | sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION; | 197 | |
309 | sz->rawir.duration += STREAMZAP_RESOLUTION / 2; | 198 | rawir.pulse = false; |
310 | sz->sum += sz->rawir.duration; | 199 | rawir.duration = ((int) value) * SZ_RESOLUTION; |
311 | sz->rawir.duration *= 1000; | 200 | rawir.duration += SZ_RESOLUTION / 2; |
312 | dev_dbg(sz->dev, "s %u\n", sz->rawir.duration); | 201 | sz->sum += rawir.duration; |
313 | sz_push(sz); | 202 | rawir.duration *= 1000; |
203 | dev_dbg(sz->dev, "s %u\n", rawir.duration); | ||
204 | sz_push(sz, rawir); | ||
314 | } | 205 | } |
315 | 206 | ||
316 | static void sz_push_half_space(struct streamzap_ir *sz, | 207 | static void sz_push_half_space(struct streamzap_ir *sz, |
317 | unsigned long value) | 208 | unsigned long value) |
318 | { | 209 | { |
319 | sz_push_full_space(sz, value & STREAMZAP_SPACE_MASK); | 210 | sz_push_full_space(sz, value & SZ_SPACE_MASK); |
320 | } | 211 | } |
321 | 212 | ||
322 | /** | 213 | /** |
@@ -330,10 +221,8 @@ static void streamzap_callback(struct urb *urb) | |||
330 | struct streamzap_ir *sz; | 221 | struct streamzap_ir *sz; |
331 | unsigned int i; | 222 | unsigned int i; |
332 | int len; | 223 | int len; |
333 | #if 0 | 224 | static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) & |
334 | static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) & | ||
335 | IR_MAX_DURATION) | 0x03000000); | 225 | IR_MAX_DURATION) | 0x03000000); |
336 | #endif | ||
337 | 226 | ||
338 | if (!urb) | 227 | if (!urb) |
339 | return; | 228 | return; |
@@ -356,57 +245,53 @@ static void streamzap_callback(struct urb *urb) | |||
356 | } | 245 | } |
357 | 246 | ||
358 | dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); | 247 | dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); |
359 | if (!sz->flush) { | 248 | for (i = 0; i < len; i++) { |
360 | for (i = 0; i < urb->actual_length; i++) { | 249 | dev_dbg(sz->dev, "sz idx %d: %x\n", |
361 | dev_dbg(sz->dev, "%d: %x\n", i, | 250 | i, (unsigned char)sz->buf_in[i]); |
362 | (unsigned char)sz->buf_in[i]); | 251 | switch (sz->decoder_state) { |
363 | switch (sz->decoder_state) { | 252 | case PulseSpace: |
364 | case PulseSpace: | 253 | if ((sz->buf_in[i] & SZ_PULSE_MASK) == |
365 | if ((sz->buf_in[i] & STREAMZAP_PULSE_MASK) == | 254 | SZ_PULSE_MASK) { |
366 | STREAMZAP_PULSE_MASK) { | 255 | sz->decoder_state = FullPulse; |
367 | sz->decoder_state = FullPulse; | 256 | continue; |
368 | continue; | 257 | } else if ((sz->buf_in[i] & SZ_SPACE_MASK) |
369 | } else if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK) | 258 | == SZ_SPACE_MASK) { |
370 | == STREAMZAP_SPACE_MASK) { | 259 | sz_push_half_pulse(sz, sz->buf_in[i]); |
371 | sz_push_half_pulse(sz, sz->buf_in[i]); | 260 | sz->decoder_state = FullSpace; |
372 | sz->decoder_state = FullSpace; | 261 | continue; |
373 | continue; | 262 | } else { |
374 | } else { | 263 | sz_push_half_pulse(sz, sz->buf_in[i]); |
375 | sz_push_half_pulse(sz, sz->buf_in[i]); | ||
376 | sz_push_half_space(sz, sz->buf_in[i]); | ||
377 | } | ||
378 | break; | ||
379 | case FullPulse: | ||
380 | sz_push_full_pulse(sz, sz->buf_in[i]); | ||
381 | sz->decoder_state = IgnorePulse; | ||
382 | break; | ||
383 | case FullSpace: | ||
384 | if (sz->buf_in[i] == STREAMZAP_TIMEOUT) { | ||
385 | sz->idle = 1; | ||
386 | streamzap_stop_timer(sz); | ||
387 | #if 0 | ||
388 | if (sz->timeout_enabled) { | ||
389 | sz->rawir.pulse = false; | ||
390 | sz->rawir.duration = timeout; | ||
391 | sz->rawir.duration *= 1000; | ||
392 | sz_push(sz); | ||
393 | } | ||
394 | #endif | ||
395 | streamzap_flush_delay_buffer(sz); | ||
396 | } else | ||
397 | sz_push_full_space(sz, sz->buf_in[i]); | ||
398 | sz->decoder_state = PulseSpace; | ||
399 | break; | ||
400 | case IgnorePulse: | ||
401 | if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) == | ||
402 | STREAMZAP_SPACE_MASK) { | ||
403 | sz->decoder_state = FullSpace; | ||
404 | continue; | ||
405 | } | ||
406 | sz_push_half_space(sz, sz->buf_in[i]); | 264 | sz_push_half_space(sz, sz->buf_in[i]); |
407 | sz->decoder_state = PulseSpace; | ||
408 | break; | ||
409 | } | 265 | } |
266 | break; | ||
267 | case FullPulse: | ||
268 | sz_push_full_pulse(sz, sz->buf_in[i]); | ||
269 | sz->decoder_state = IgnorePulse; | ||
270 | break; | ||
271 | case FullSpace: | ||
272 | if (sz->buf_in[i] == SZ_TIMEOUT) { | ||
273 | DEFINE_IR_RAW_EVENT(rawir); | ||
274 | |||
275 | rawir.pulse = false; | ||
276 | rawir.duration = timeout; | ||
277 | sz->idle = true; | ||
278 | if (sz->timeout_enabled) | ||
279 | sz_push(sz, rawir); | ||
280 | ir_raw_event_handle(sz->idev); | ||
281 | } else { | ||
282 | sz_push_full_space(sz, sz->buf_in[i]); | ||
283 | } | ||
284 | sz->decoder_state = PulseSpace; | ||
285 | break; | ||
286 | case IgnorePulse: | ||
287 | if ((sz->buf_in[i] & SZ_SPACE_MASK) == | ||
288 | SZ_SPACE_MASK) { | ||
289 | sz->decoder_state = FullSpace; | ||
290 | continue; | ||
291 | } | ||
292 | sz_push_half_space(sz, sz->buf_in[i]); | ||
293 | sz->decoder_state = PulseSpace; | ||
294 | break; | ||
410 | } | 295 | } |
411 | } | 296 | } |
412 | 297 | ||
@@ -446,12 +331,11 @@ static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz) | |||
446 | 331 | ||
447 | props->priv = sz; | 332 | props->priv = sz; |
448 | props->driver_type = RC_DRIVER_IR_RAW; | 333 | props->driver_type = RC_DRIVER_IR_RAW; |
449 | /* FIXME: not sure about supported protocols, check on this */ | 334 | props->allowed_protos = IR_TYPE_ALL; |
450 | props->allowed_protos = IR_TYPE_RC5 | IR_TYPE_RC6; | ||
451 | 335 | ||
452 | sz->props = props; | 336 | sz->props = props; |
453 | 337 | ||
454 | ret = ir_input_register(idev, RC_MAP_RC5_STREAMZAP, props, DRIVER_NAME); | 338 | ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME); |
455 | if (ret < 0) { | 339 | if (ret < 0) { |
456 | dev_err(dev, "remote input device register failed\n"); | 340 | dev_err(dev, "remote input device register failed\n"); |
457 | goto irdev_failed; | 341 | goto irdev_failed; |
@@ -467,29 +351,6 @@ idev_alloc_failed: | |||
467 | return NULL; | 351 | return NULL; |
468 | } | 352 | } |
469 | 353 | ||
470 | static int streamzap_delay_buf_init(struct streamzap_ir *sz) | ||
471 | { | ||
472 | int ret; | ||
473 | |||
474 | ret = kfifo_alloc(&sz->fifo, sizeof(int) * SZ_BUF_LEN, | ||
475 | GFP_KERNEL); | ||
476 | if (ret == 0) | ||
477 | sz->fifo_initialized = 1; | ||
478 | |||
479 | return ret; | ||
480 | } | ||
481 | |||
482 | static void streamzap_start_flush_timer(struct streamzap_ir *sz) | ||
483 | { | ||
484 | sz->flush_timer.expires = jiffies + HZ; | ||
485 | sz->flush = true; | ||
486 | add_timer(&sz->flush_timer); | ||
487 | |||
488 | sz->urb_in->dev = sz->usbdev; | ||
489 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) | ||
490 | dev_err(sz->dev, "urb submit failed\n"); | ||
491 | } | ||
492 | |||
493 | /** | 354 | /** |
494 | * streamzap_probe | 355 | * streamzap_probe |
495 | * | 356 | * |
@@ -575,35 +436,21 @@ static int __devinit streamzap_probe(struct usb_interface *intf, | |||
575 | snprintf(name + strlen(name), sizeof(name) - strlen(name), | 436 | snprintf(name + strlen(name), sizeof(name) - strlen(name), |
576 | " %s", buf); | 437 | " %s", buf); |
577 | 438 | ||
578 | retval = streamzap_delay_buf_init(sz); | ||
579 | if (retval) { | ||
580 | dev_err(&intf->dev, "%s: delay buffer init failed\n", __func__); | ||
581 | goto free_urb_in; | ||
582 | } | ||
583 | |||
584 | sz->idev = streamzap_init_input_dev(sz); | 439 | sz->idev = streamzap_init_input_dev(sz); |
585 | if (!sz->idev) | 440 | if (!sz->idev) |
586 | goto input_dev_fail; | 441 | goto input_dev_fail; |
587 | 442 | ||
588 | sz->idle = true; | 443 | sz->idle = true; |
589 | sz->decoder_state = PulseSpace; | 444 | sz->decoder_state = PulseSpace; |
445 | /* FIXME: don't yet have a way to set this */ | ||
446 | sz->timeout_enabled = true; | ||
590 | #if 0 | 447 | #if 0 |
591 | /* not yet supported, depends on patches from maxim */ | 448 | /* not yet supported, depends on patches from maxim */ |
592 | /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */ | 449 | /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */ |
593 | sz->timeout_enabled = false; | 450 | sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000; |
594 | sz->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000; | 451 | sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000; |
595 | sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000; | ||
596 | #endif | 452 | #endif |
597 | 453 | ||
598 | init_timer(&sz->delay_timer); | ||
599 | sz->delay_timer.function = streamzap_delay_timeout; | ||
600 | sz->delay_timer.data = (unsigned long)sz; | ||
601 | spin_lock_init(&sz->timer_lock); | ||
602 | |||
603 | init_timer(&sz->flush_timer); | ||
604 | sz->flush_timer.function = streamzap_flush_timeout; | ||
605 | sz->flush_timer.data = (unsigned long)sz; | ||
606 | |||
607 | do_gettimeofday(&sz->signal_start); | 454 | do_gettimeofday(&sz->signal_start); |
608 | 455 | ||
609 | /* Complete final initialisations */ | 456 | /* Complete final initialisations */ |
@@ -615,16 +462,18 @@ static int __devinit streamzap_probe(struct usb_interface *intf, | |||
615 | 462 | ||
616 | usb_set_intfdata(intf, sz); | 463 | usb_set_intfdata(intf, sz); |
617 | 464 | ||
618 | streamzap_start_flush_timer(sz); | 465 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) |
466 | dev_err(sz->dev, "urb submit failed\n"); | ||
619 | 467 | ||
620 | dev_info(sz->dev, "Registered %s on usb%d:%d\n", name, | 468 | dev_info(sz->dev, "Registered %s on usb%d:%d\n", name, |
621 | usbdev->bus->busnum, usbdev->devnum); | 469 | usbdev->bus->busnum, usbdev->devnum); |
622 | 470 | ||
471 | /* Load the streamzap not-quite-rc5 decoder too */ | ||
472 | load_rc5_sz_decode(); | ||
473 | |||
623 | return 0; | 474 | return 0; |
624 | 475 | ||
625 | input_dev_fail: | 476 | input_dev_fail: |
626 | kfifo_free(&sz->fifo); | ||
627 | free_urb_in: | ||
628 | usb_free_urb(sz->urb_in); | 477 | usb_free_urb(sz->urb_in); |
629 | free_buf_in: | 478 | free_buf_in: |
630 | usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in); | 479 | usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in); |
@@ -654,13 +503,6 @@ static void streamzap_disconnect(struct usb_interface *interface) | |||
654 | if (!sz) | 503 | if (!sz) |
655 | return; | 504 | return; |
656 | 505 | ||
657 | if (sz->flush) { | ||
658 | sz->flush = false; | ||
659 | del_timer_sync(&sz->flush_timer); | ||
660 | } | ||
661 | |||
662 | streamzap_stop_timer(sz); | ||
663 | |||
664 | sz->usbdev = NULL; | 506 | sz->usbdev = NULL; |
665 | ir_input_unregister(sz->idev); | 507 | ir_input_unregister(sz->idev); |
666 | usb_kill_urb(sz->urb_in); | 508 | usb_kill_urb(sz->urb_in); |
@@ -674,13 +516,6 @@ static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) | |||
674 | { | 516 | { |
675 | struct streamzap_ir *sz = usb_get_intfdata(intf); | 517 | struct streamzap_ir *sz = usb_get_intfdata(intf); |
676 | 518 | ||
677 | if (sz->flush) { | ||
678 | sz->flush = false; | ||
679 | del_timer_sync(&sz->flush_timer); | ||
680 | } | ||
681 | |||
682 | streamzap_stop_timer(sz); | ||
683 | |||
684 | usb_kill_urb(sz->urb_in); | 519 | usb_kill_urb(sz->urb_in); |
685 | 520 | ||
686 | return 0; | 521 | return 0; |
@@ -690,13 +525,6 @@ static int streamzap_resume(struct usb_interface *intf) | |||
690 | { | 525 | { |
691 | struct streamzap_ir *sz = usb_get_intfdata(intf); | 526 | struct streamzap_ir *sz = usb_get_intfdata(intf); |
692 | 527 | ||
693 | if (sz->fifo_initialized) | ||
694 | kfifo_reset(&sz->fifo); | ||
695 | |||
696 | sz->flush_timer.expires = jiffies + HZ; | ||
697 | sz->flush = true; | ||
698 | add_timer(&sz->flush_timer); | ||
699 | |||
700 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { | 528 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { |
701 | dev_err(sz->dev, "Error sumbiting urb\n"); | 529 | dev_err(sz->dev, "Error sumbiting urb\n"); |
702 | return -EIO; | 530 | return -EIO; |