]>
Commit | Line | Data |
---|---|---|
9ea53b74 | 1 | /* |
931e39a1 | 2 | * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX) |
9ea53b74 ML |
3 | * |
4 | * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@gmail.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License as | |
8 | * published by the Free Software Foundation; either version 2 of the | |
9 | * License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
19 | * USA | |
20 | */ | |
21 | ||
22 | #include <linux/kernel.h> | |
23 | #include <linux/module.h> | |
24 | #include <linux/pnp.h> | |
25 | #include <linux/io.h> | |
26 | #include <linux/interrupt.h> | |
27 | #include <linux/sched.h> | |
931e39a1 ML |
28 | #include <linux/slab.h> |
29 | #include <linux/input.h> | |
30 | #include <media/ir-core.h> | |
31 | #include <media/ir-common.h> | |
32 | #include "ene_ir.h" | |
9ea53b74 ML |
33 | |
34 | ||
35 | static int sample_period = -1; | |
36 | static int enable_idle = 1; | |
9ea53b74 ML |
37 | static int input = 1; |
38 | static int debug; | |
39 | static int txsim; | |
40 | ||
9ea53b74 | 41 | static int ene_irq_status(struct ene_device *dev); |
9ea53b74 ML |
42 | |
43 | /* read a hardware register */ | |
44 | static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) | |
45 | { | |
46 | u8 retval; | |
47 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | |
48 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | |
49 | retval = inb(dev->hw_io + ENE_IO); | |
50 | ||
51 | ene_dbg_verbose("reg %04x == %02x", reg, retval); | |
52 | return retval; | |
53 | } | |
54 | ||
55 | /* write a hardware register */ | |
56 | static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value) | |
57 | { | |
58 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | |
59 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | |
60 | outb(value, dev->hw_io + ENE_IO); | |
61 | ||
62 | ene_dbg_verbose("reg %04x <- %02x", reg, value); | |
63 | } | |
64 | ||
65 | /* change specific bits in hardware register */ | |
66 | static void ene_hw_write_reg_mask(struct ene_device *dev, | |
67 | u16 reg, u8 value, u8 mask) | |
68 | { | |
69 | u8 regvalue; | |
70 | ||
71 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | |
72 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | |
73 | ||
74 | regvalue = inb(dev->hw_io + ENE_IO) & ~mask; | |
75 | regvalue |= (value & mask); | |
76 | outb(regvalue, dev->hw_io + ENE_IO); | |
77 | ||
78 | ene_dbg_verbose("reg %04x <- %02x (mask=%02x)", reg, value, mask); | |
79 | } | |
80 | ||
81 | /* detect hardware features */ | |
82 | static int ene_hw_detect(struct ene_device *dev) | |
83 | { | |
84 | u8 chip_major, chip_minor; | |
85 | u8 hw_revision, old_ver; | |
86 | u8 tmp; | |
87 | u8 fw_capabilities; | |
931e39a1 | 88 | int pll_freq; |
9ea53b74 ML |
89 | |
90 | tmp = ene_hw_read_reg(dev, ENE_HW_UNK); | |
91 | ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR); | |
92 | ||
93 | chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR); | |
94 | chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR); | |
95 | ||
96 | ene_hw_write_reg(dev, ENE_HW_UNK, tmp); | |
97 | hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION); | |
98 | old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD); | |
99 | ||
931e39a1 ML |
100 | pll_freq = (ene_hw_read_reg(dev, ENE_PLLFRH) << 4) + |
101 | (ene_hw_read_reg(dev, ENE_PLLFRL) >> 4); | |
102 | ||
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 | ||
9ea53b74 ML |
111 | if (hw_revision == 0xFF) { |
112 | ||
113 | ene_printk(KERN_WARNING, "device seems to be disabled\n"); | |
114 | ene_printk(KERN_WARNING, | |
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; | |
118 | } | |
119 | ||
120 | if (chip_major == 0x33) { | |
121 | ene_printk(KERN_WARNING, "chips 0x33xx aren't supported\n"); | |
122 | return -ENODEV; | |
123 | } | |
124 | ||
125 | if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { | |
126 | dev->hw_revision = ENE_HW_C; | |
127 | } else if (old_ver == 0x24 && hw_revision == 0xC0) { | |
128 | dev->hw_revision = ENE_HW_B; | |
129 | ene_printk(KERN_NOTICE, "KB3926B detected\n"); | |
130 | } else { | |
131 | dev->hw_revision = ENE_HW_D; | |
132 | ene_printk(KERN_WARNING, | |
133 | "unknown ENE chip detected, assuming KB3926D\n"); | |
134 | ene_printk(KERN_WARNING, | |
135 | "driver support might be not complete"); | |
136 | ||
137 | } | |
138 | ||
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 */ | |
144 | if (dev->hw_revision < ENE_HW_C) | |
145 | return 0; | |
146 | ||
147 | fw_capabilities = ene_hw_read_reg(dev, ENE_FW2); | |
148 | ene_dbg("Firmware capabilities: %02x", fw_capabilities); | |
149 | ||
150 | dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; | |
151 | dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; | |
152 | ||
153 | dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && | |
154 | (fw_capabilities & ENE_FW2_FAN_AS_NRML_IN); | |
155 | ||
156 | ene_printk(KERN_NOTICE, "hardware features:\n"); | |
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 | ||
163 | if (dev->hw_learning_and_tx_capable) { | |
164 | ene_printk(KERN_WARNING, | |
165 | "Device supports transmitting, but that support is\n"); | |
166 | ene_printk(KERN_WARNING, | |
167 | "lightly tested. Please test it and mail\n"); | |
168 | ene_printk(KERN_WARNING, | |
169 | "lirc-list@lists.sourceforge.net\n"); | |
170 | } | |
171 | return 0; | |
172 | } | |
173 | ||
174 | /* this enables/disables IR input via gpio40*/ | |
931e39a1 | 175 | static void ene_enable_gpio40_receive(struct ene_device *dev, int enable) |
9ea53b74 ML |
176 | { |
177 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ? | |
178 | 0 : ENE_CIR_CONF2_GPIO40DIS, | |
179 | ENE_CIR_CONF2_GPIO40DIS); | |
180 | } | |
181 | ||
182 | /* this enables/disables IR via standard input */ | |
931e39a1 | 183 | static void ene_enable_normal_receive(struct ene_device *dev, int enable) |
9ea53b74 ML |
184 | { |
185 | ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0); | |
186 | } | |
187 | ||
188 | /* this enables/disables IR input via unused fan tachtometer input */ | |
931e39a1 | 189 | static void ene_enable_fan_receive(struct ene_device *dev, int enable) |
9ea53b74 ML |
190 | { |
191 | if (!enable) | |
192 | ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); | |
193 | else { | |
194 | ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); | |
195 | ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); | |
196 | } | |
197 | dev->rx_fan_input_inuse = enable; | |
198 | } | |
199 | ||
200 | ||
931e39a1 | 201 | /* Sense current received carrier */ |
9ea53b74 ML |
202 | static int ene_rx_sense_carrier(struct ene_device *dev) |
203 | { | |
204 | int period = ene_hw_read_reg(dev, ENE_RX_CARRIER); | |
205 | int carrier; | |
206 | ene_dbg("RX: hardware carrier period = %02x", period); | |
207 | ||
208 | if (!(period & ENE_RX_CARRIER_VALID)) | |
209 | return 0; | |
210 | ||
211 | period &= ~ENE_RX_CARRIER_VALID; | |
212 | ||
213 | if (!period) | |
214 | return 0; | |
215 | ||
216 | carrier = 2000000 / period; | |
217 | ene_dbg("RX: sensed carrier = %d Hz", carrier); | |
218 | return carrier; | |
219 | } | |
220 | ||
221 | /* determine which input to use*/ | |
222 | static void ene_rx_set_inputs(struct ene_device *dev) | |
223 | { | |
931e39a1 | 224 | int learning_mode = dev->learning_enabled; |
9ea53b74 | 225 | |
931e39a1 | 226 | ene_dbg("RX: setup receiver, learning mode = %d", learning_mode); |
9ea53b74 | 227 | |
931e39a1 | 228 | ene_enable_normal_receive(dev, 1); |
9ea53b74 ML |
229 | |
230 | /* old hardware doesn't support learning mode for sure */ | |
231 | if (dev->hw_revision <= ENE_HW_B) | |
232 | return; | |
233 | ||
931e39a1 | 234 | /* receiver not learning capable, still set gpio40 correctly */ |
9ea53b74 | 235 | if (!dev->hw_learning_and_tx_capable) { |
931e39a1 | 236 | ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning); |
9ea53b74 ML |
237 | return; |
238 | } | |
239 | ||
240 | /* enable learning mode */ | |
241 | if (learning_mode) { | |
931e39a1 | 242 | ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning); |
9ea53b74 ML |
243 | |
244 | /* fan input is not used for learning */ | |
245 | if (dev->hw_fan_as_normal_input) | |
931e39a1 | 246 | ene_enable_fan_receive(dev, 0); |
9ea53b74 ML |
247 | |
248 | /* disable learning mode */ | |
249 | } else { | |
250 | if (dev->hw_fan_as_normal_input) { | |
931e39a1 ML |
251 | ene_enable_fan_receive(dev, 1); |
252 | ene_enable_normal_receive(dev, 0); | |
9ea53b74 | 253 | } else |
931e39a1 | 254 | ene_enable_gpio40_receive(dev, |
9ea53b74 ML |
255 | !dev->hw_gpio40_learning); |
256 | } | |
257 | ||
258 | /* set few additional settings for this mode */ | |
259 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_mode ? | |
260 | ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); | |
261 | ||
262 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ? | |
263 | ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); | |
931e39a1 ML |
264 | |
265 | if (dev->rx_fan_input_inuse) { | |
266 | dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000; | |
267 | ||
268 | dev->props->timeout = | |
269 | ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000; | |
270 | } else { | |
271 | dev->props->rx_resolution = sample_period * 1000; | |
272 | dev->props->timeout = ENE_MAXGAP * 1000; | |
273 | } | |
9ea53b74 ML |
274 | } |
275 | ||
276 | /* Enable the device for receive */ | |
277 | static void ene_rx_enable(struct ene_device *dev) | |
278 | { | |
279 | u8 reg_value; | |
280 | ||
281 | if (dev->hw_revision < ENE_HW_C) { | |
282 | ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1); | |
283 | ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01); | |
284 | } else { | |
285 | reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0; | |
286 | reg_value |= ENEC_IRQ_UNK_EN; | |
287 | reg_value &= ~ENEC_IRQ_STATUS; | |
288 | reg_value |= (dev->irq & ENEC_IRQ_MASK); | |
289 | ene_hw_write_reg(dev, ENEC_IRQ, reg_value); | |
290 | ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63); | |
291 | } | |
292 | ||
293 | ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); | |
294 | ene_rx_set_inputs(dev); | |
295 | ||
296 | /* set sampling period */ | |
297 | ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); | |
298 | ||
299 | /* ack any pending irqs - just in case */ | |
300 | ene_irq_status(dev); | |
301 | ||
9ea53b74 ML |
302 | /* enable firmware bits */ |
303 | ene_hw_write_reg_mask(dev, ENE_FW1, | |
304 | ENE_FW1_ENABLE | ENE_FW1_IRQ, | |
305 | ENE_FW1_ENABLE | ENE_FW1_IRQ); | |
931e39a1 ML |
306 | |
307 | /* enter idle mode */ | |
308 | ir_raw_event_set_idle(dev->idev, 1); | |
309 | ir_raw_event_reset(dev->idev); | |
310 | ||
9ea53b74 ML |
311 | } |
312 | ||
931e39a1 | 313 | /* Disable the device receiver */ |
9ea53b74 ML |
314 | static void ene_rx_disable(struct ene_device *dev) |
315 | { | |
316 | /* disable inputs */ | |
931e39a1 | 317 | ene_enable_normal_receive(dev, 0); |
9ea53b74 ML |
318 | |
319 | if (dev->hw_fan_as_normal_input) | |
931e39a1 | 320 | ene_enable_fan_receive(dev, 0); |
9ea53b74 ML |
321 | |
322 | /* disable hardware IRQ and firmware flag */ | |
323 | ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); | |
324 | ||
931e39a1 ML |
325 | ir_raw_event_set_idle(dev->idev, 1); |
326 | ir_raw_event_reset(dev->idev); | |
9ea53b74 ML |
327 | } |
328 | ||
9ea53b74 ML |
329 | |
330 | /* prepare transmission */ | |
331 | static void ene_tx_prepare(struct ene_device *dev) | |
332 | { | |
333 | u8 conf1; | |
334 | ||
335 | conf1 = ene_hw_read_reg(dev, ENE_CIR_CONF1); | |
336 | dev->saved_conf1 = conf1; | |
337 | ||
338 | if (dev->hw_revision == ENE_HW_C) | |
339 | conf1 &= ~ENE_CIR_CONF1_TX_CLEAR; | |
340 | ||
341 | /* Enable TX engine */ | |
342 | conf1 |= ENE_CIR_CONF1_TX_ON; | |
343 | ||
344 | /* Set carrier */ | |
345 | if (dev->tx_period) { | |
346 | ||
931e39a1 ML |
347 | /* NOTE: duty cycle handling is just a guess, it might |
348 | not be aviable. Default values were tested */ | |
9ea53b74 ML |
349 | int tx_period_in500ns = dev->tx_period * 2; |
350 | ||
351 | int tx_pulse_width_in_500ns = | |
352 | tx_period_in500ns / (100 / dev->tx_duty_cycle); | |
353 | ||
354 | if (!tx_pulse_width_in_500ns) | |
355 | tx_pulse_width_in_500ns = 1; | |
356 | ||
357 | ene_dbg("TX: pulse distance = %d * 500 ns", tx_period_in500ns); | |
358 | ene_dbg("TX: pulse width = %d * 500 ns", | |
359 | tx_pulse_width_in_500ns); | |
360 | ||
361 | ene_hw_write_reg(dev, ENE_TX_PERIOD, ENE_TX_PERIOD_UNKBIT | | |
362 | tx_period_in500ns); | |
363 | ||
364 | ene_hw_write_reg(dev, ENE_TX_PERIOD_PULSE, | |
365 | tx_pulse_width_in_500ns); | |
366 | ||
367 | conf1 |= ENE_CIR_CONF1_TX_CARR; | |
368 | } else | |
369 | conf1 &= ~ENE_CIR_CONF1_TX_CARR; | |
370 | ||
371 | ene_hw_write_reg(dev, ENE_CIR_CONF1, conf1); | |
9ea53b74 ML |
372 | |
373 | } | |
374 | ||
375 | /* end transmission */ | |
376 | static void ene_tx_complete(struct ene_device *dev) | |
377 | { | |
378 | ene_hw_write_reg(dev, ENE_CIR_CONF1, dev->saved_conf1); | |
931e39a1 | 379 | dev->tx_buffer = NULL; |
9ea53b74 ML |
380 | } |
381 | ||
382 | /* set transmit mask */ | |
931e39a1 | 383 | static void ene_tx_hw_set_transmiter_mask(struct ene_device *dev) |
9ea53b74 ML |
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 | ||
398 | /* TX one sample - must be called with dev->hw_lock*/ | |
399 | static void ene_tx_sample(struct ene_device *dev) | |
400 | { | |
401 | u8 raw_tx; | |
402 | u32 sample; | |
403 | ||
931e39a1 ML |
404 | if (!dev->tx_buffer) { |
405 | ene_dbg("TX: attempt to transmit NULL buffer"); | |
9ea53b74 ML |
406 | return; |
407 | } | |
408 | ||
409 | /* Grab next TX sample */ | |
410 | if (!dev->tx_sample) { | |
411 | again: | |
412 | if (dev->tx_pos == dev->tx_len + 1) { | |
413 | if (!dev->tx_done) { | |
414 | ene_dbg("TX: no more data to send"); | |
415 | dev->tx_done = 1; | |
416 | goto exit; | |
417 | } else { | |
418 | ene_dbg("TX: last sample sent by hardware"); | |
419 | ene_tx_complete(dev); | |
420 | complete(&dev->tx_complete); | |
421 | return; | |
422 | } | |
423 | } | |
424 | ||
425 | sample = dev->tx_buffer[dev->tx_pos++]; | |
426 | dev->tx_sample_pulse = !dev->tx_sample_pulse; | |
427 | ||
428 | ene_dbg("TX: sample %8d (%s)", sample, dev->tx_sample_pulse ? | |
429 | "pulse" : "space"); | |
430 | ||
431 | dev->tx_sample = DIV_ROUND_CLOSEST(sample, ENE_TX_SMPL_PERIOD); | |
432 | ||
433 | /* guard against too short samples */ | |
434 | if (!dev->tx_sample) | |
435 | goto again; | |
436 | } | |
437 | ||
438 | raw_tx = min(dev->tx_sample , (unsigned int)ENE_TX_SMLP_MASK); | |
439 | dev->tx_sample -= raw_tx; | |
440 | ||
441 | if (dev->tx_sample_pulse) | |
442 | raw_tx |= ENE_TX_PULSE_MASK; | |
443 | ||
444 | ene_hw_write_reg(dev, ENE_TX_INPUT1 + dev->tx_reg, raw_tx); | |
445 | dev->tx_reg = !dev->tx_reg; | |
446 | exit: | |
447 | /* simulate TX done interrupt */ | |
448 | if (txsim) | |
449 | mod_timer(&dev->tx_sim_timer, jiffies + HZ / 500); | |
450 | } | |
451 | ||
452 | /* timer to simulate tx done interrupt */ | |
453 | static void ene_tx_irqsim(unsigned long data) | |
454 | { | |
455 | struct ene_device *dev = (struct ene_device *)data; | |
456 | unsigned long flags; | |
457 | ||
458 | spin_lock_irqsave(&dev->hw_lock, flags); | |
459 | ene_tx_sample(dev); | |
460 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
461 | } | |
462 | ||
463 | ||
464 | /* read irq status and ack it */ | |
465 | static int ene_irq_status(struct ene_device *dev) | |
466 | { | |
467 | u8 irq_status; | |
468 | u8 fw_flags1, fw_flags2; | |
469 | int cur_rx_pointer; | |
470 | int retval = 0; | |
471 | ||
472 | fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); | |
473 | cur_rx_pointer = !!(fw_flags2 & ENE_FW2_BUF_HIGH); | |
474 | ||
475 | if (dev->hw_revision < ENE_HW_C) { | |
476 | irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS); | |
477 | ||
478 | if (!(irq_status & ENEB_IRQ_STATUS_IR)) | |
479 | return 0; | |
480 | ||
481 | ene_hw_write_reg(dev, ENEB_IRQ_STATUS, | |
482 | irq_status & ~ENEB_IRQ_STATUS_IR); | |
483 | dev->rx_pointer = cur_rx_pointer; | |
484 | return ENE_IRQ_RX; | |
485 | } | |
486 | ||
487 | irq_status = ene_hw_read_reg(dev, ENEC_IRQ); | |
488 | ||
489 | if (!(irq_status & ENEC_IRQ_STATUS)) | |
490 | return 0; | |
491 | ||
492 | /* original driver does that twice - a workaround ? */ | |
493 | ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); | |
494 | ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); | |
495 | ||
496 | /* clear unknown flag in F8F9 */ | |
497 | if (fw_flags2 & ENE_FW2_IRQ_CLR) | |
498 | ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR); | |
499 | ||
500 | /* check if this is a TX interrupt */ | |
501 | fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); | |
502 | if (fw_flags1 & ENE_FW1_TXIRQ) { | |
503 | ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); | |
504 | retval |= ENE_IRQ_TX; | |
505 | } | |
506 | ||
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; | |
522 | } | |
523 | ||
524 | /* interrupt handler */ | |
525 | static irqreturn_t ene_isr(int irq, void *data) | |
526 | { | |
527 | u16 hw_value; | |
528 | int i, hw_sample; | |
529 | int pulse; | |
530 | int irq_status; | |
531 | unsigned long flags; | |
532 | int carrier = 0; | |
533 | irqreturn_t retval = IRQ_NONE; | |
534 | struct ene_device *dev = (struct ene_device *)data; | |
931e39a1 | 535 | struct ir_raw_event ev; |
9ea53b74 ML |
536 | |
537 | ||
538 | spin_lock_irqsave(&dev->hw_lock, flags); | |
539 | irq_status = ene_irq_status(dev); | |
540 | ||
541 | if (!irq_status) | |
542 | goto unlock; | |
543 | ||
544 | retval = IRQ_HANDLED; | |
545 | ||
546 | if (irq_status & ENE_IRQ_TX) { | |
547 | ||
548 | if (!dev->hw_learning_and_tx_capable) { | |
549 | ene_dbg("TX interrupt on unsupported device!"); | |
550 | goto unlock; | |
551 | } | |
552 | ene_tx_sample(dev); | |
553 | } | |
554 | ||
555 | if (!(irq_status & ENE_IRQ_RX)) | |
556 | goto unlock; | |
557 | ||
558 | ||
931e39a1 | 559 | if (dev->carrier_detect_enabled || debug) |
9ea53b74 | 560 | carrier = ene_rx_sense_carrier(dev); |
931e39a1 ML |
561 | #if 0 |
562 | /* TODO */ | |
563 | if (dev->carrier_detect_enabled && carrier) | |
564 | ir_raw_event_report_frequency(dev->idev, carrier); | |
565 | #endif | |
9ea53b74 ML |
566 | |
567 | for (i = 0; i < ENE_SAMPLES_SIZE; i++) { | |
568 | hw_value = ene_hw_read_reg(dev, | |
569 | ENE_SAMPLE_BUFFER + dev->rx_pointer * 4 + i); | |
570 | ||
571 | if (dev->rx_fan_input_inuse) { | |
572 | /* read high part of the sample */ | |
573 | hw_value |= ene_hw_read_reg(dev, | |
574 | ENE_SAMPLE_BUFFER_FAN + | |
575 | dev->rx_pointer * 4 + i) << 8; | |
576 | pulse = hw_value & ENE_FAN_SMPL_PULS_MSK; | |
577 | ||
578 | /* clear space bit, and other unused bits */ | |
579 | hw_value &= ENE_FAN_VALUE_MASK; | |
580 | hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; | |
581 | ||
582 | } else { | |
583 | pulse = !(hw_value & ENE_SAMPLE_SPC_MASK); | |
584 | hw_value &= ENE_SAMPLE_VALUE_MASK; | |
585 | hw_sample = hw_value * sample_period; | |
931e39a1 ML |
586 | |
587 | if (dev->rx_period_adjust) { | |
588 | hw_sample *= (100 - dev->rx_period_adjust); | |
589 | hw_sample /= 100; | |
590 | } | |
9ea53b74 ML |
591 | } |
592 | /* no more data */ | |
593 | if (!(hw_value)) | |
594 | break; | |
595 | ||
931e39a1 ML |
596 | ene_dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space"); |
597 | ||
598 | ||
599 | ev.duration = hw_sample * 1000; | |
600 | ev.pulse = pulse; | |
601 | ir_raw_event_store_with_filter(dev->idev, &ev); | |
9ea53b74 | 602 | } |
931e39a1 ML |
603 | |
604 | ir_raw_event_handle(dev->idev); | |
9ea53b74 ML |
605 | unlock: |
606 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
607 | return retval; | |
608 | } | |
609 | ||
610 | /* Initialize default settings */ | |
611 | static void ene_setup_settings(struct ene_device *dev) | |
612 | { | |
9ea53b74 ML |
613 | dev->tx_period = 32; |
614 | dev->tx_duty_cycle = 25; /*%*/ | |
615 | dev->transmitter_mask = 3; | |
616 | ||
617 | /* Force learning mode if (input == 2), otherwise | |
618 | let user set it with LIRC_SET_REC_CARRIER */ | |
619 | dev->learning_enabled = | |
620 | (input == 2 && dev->hw_learning_and_tx_capable); | |
621 | ||
9ea53b74 | 622 | dev->rx_pointer = -1; |
9ea53b74 ML |
623 | |
624 | } | |
625 | ||
626 | /* outside interface: called on first open*/ | |
627 | static int ene_open(void *data) | |
628 | { | |
629 | struct ene_device *dev = (struct ene_device *)data; | |
630 | unsigned long flags; | |
631 | ||
632 | spin_lock_irqsave(&dev->hw_lock, flags); | |
633 | dev->in_use = 1; | |
634 | ene_setup_settings(dev); | |
635 | ene_rx_enable(dev); | |
636 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
637 | return 0; | |
638 | } | |
639 | ||
640 | /* outside interface: called on device close*/ | |
641 | static void ene_close(void *data) | |
642 | { | |
643 | struct ene_device *dev = (struct ene_device *)data; | |
644 | unsigned long flags; | |
645 | spin_lock_irqsave(&dev->hw_lock, flags); | |
646 | ||
647 | ene_rx_disable(dev); | |
648 | dev->in_use = 0; | |
649 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
650 | } | |
651 | ||
931e39a1 ML |
652 | /* outside interface: set transmitter mask */ |
653 | static int ene_set_tx_mask(void *data, u32 tx_mask) | |
9ea53b74 | 654 | { |
931e39a1 | 655 | struct ene_device *dev = (struct ene_device *)data; |
9ea53b74 | 656 | unsigned long flags; |
931e39a1 ML |
657 | ene_dbg("TX: attempt to set transmitter mask %02x", tx_mask); |
658 | ||
659 | /* invalid txmask */ | |
660 | if (!tx_mask || tx_mask & ~0x3) { | |
661 | ene_dbg("TX: invalid mask"); | |
662 | /* return count of transmitters */ | |
663 | return 2; | |
9ea53b74 ML |
664 | } |
665 | ||
931e39a1 ML |
666 | spin_lock_irqsave(&dev->hw_lock, flags); |
667 | dev->transmitter_mask = tx_mask; | |
668 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
669 | return 0; | |
670 | } | |
9ea53b74 | 671 | |
931e39a1 ML |
672 | /* outside interface : set tx carrier */ |
673 | static int ene_set_tx_carrier(void *data, u32 carrier) | |
674 | { | |
675 | struct ene_device *dev = (struct ene_device *)data; | |
676 | unsigned long flags; | |
677 | u32 period = 1000000 / carrier; /* (1 / freq) (* # usec in 1 sec) */ | |
9ea53b74 | 678 | |
931e39a1 | 679 | ene_dbg("TX: attempt to set tx carrier to %d kHz", carrier); |
9ea53b74 | 680 | |
931e39a1 ML |
681 | if (period && (period > ENE_TX_PERIOD_MAX || |
682 | period < ENE_TX_PERIOD_MIN)) { | |
9ea53b74 | 683 | |
931e39a1 ML |
684 | ene_dbg("TX: out of range %d-%d carrier, " |
685 | "falling back to 32 kHz", | |
686 | 1000 / ENE_TX_PERIOD_MIN, | |
687 | 1000 / ENE_TX_PERIOD_MAX); | |
9ea53b74 | 688 | |
931e39a1 | 689 | period = 32; /* this is just a coincidence!!! */ |
9ea53b74 | 690 | } |
931e39a1 | 691 | ene_dbg("TX: set carrier to %d kHz", carrier); |
9ea53b74 | 692 | |
931e39a1 ML |
693 | spin_lock_irqsave(&dev->hw_lock, flags); |
694 | dev->tx_period = period; | |
695 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
696 | return 0; | |
9ea53b74 ML |
697 | } |
698 | ||
931e39a1 ML |
699 | |
700 | /* outside interface: enable learning mode */ | |
701 | static int ene_set_learning_mode(void *data, int enable) | |
9ea53b74 | 702 | { |
931e39a1 | 703 | struct ene_device *dev = (struct ene_device *)data; |
9ea53b74 | 704 | unsigned long flags; |
931e39a1 ML |
705 | if (enable == dev->learning_enabled) |
706 | return 0; | |
9ea53b74 | 707 | |
931e39a1 ML |
708 | spin_lock_irqsave(&dev->hw_lock, flags); |
709 | dev->learning_enabled = enable; | |
710 | ene_rx_set_inputs(dev); | |
711 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
712 | return 0; | |
713 | } | |
9ea53b74 | 714 | |
931e39a1 ML |
715 | /* outside interface: set rec carrier */ |
716 | static int ene_set_rec_carrier(void *data, u32 min, u32 max) | |
717 | { | |
718 | struct ene_device *dev = (struct ene_device *)data; | |
719 | ene_set_learning_mode(dev, | |
720 | max > ENE_NORMAL_RX_HI || min < ENE_NORMAL_RX_LOW); | |
721 | return 0; | |
722 | } | |
9ea53b74 | 723 | |
931e39a1 ML |
724 | /* outside interface: enable or disable idle mode */ |
725 | static void ene_rx_set_idle(void *data, int idle) | |
726 | { | |
727 | struct ene_device *dev = (struct ene_device *)data; | |
728 | ene_dbg("%sabling idle mode", idle ? "en" : "dis"); | |
9ea53b74 | 729 | |
931e39a1 ML |
730 | ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, |
731 | (enable_idle && idle) ? 0 : ENE_CIR_SAMPLE_OVERFLOW, | |
732 | ENE_CIR_SAMPLE_OVERFLOW); | |
733 | } | |
9ea53b74 | 734 | |
9ea53b74 | 735 | |
931e39a1 ML |
736 | /* outside interface: transmit */ |
737 | static int ene_transmit(void *data, int *buf, u32 n) | |
738 | { | |
739 | struct ene_device *dev = (struct ene_device *)data; | |
740 | unsigned long flags; | |
741 | ||
742 | dev->tx_buffer = buf; | |
9ea53b74 ML |
743 | dev->tx_len = n / sizeof(int); |
744 | dev->tx_pos = 0; | |
745 | dev->tx_reg = 0; | |
746 | dev->tx_done = 0; | |
747 | dev->tx_sample = 0; | |
748 | dev->tx_sample_pulse = 0; | |
749 | ||
750 | ene_dbg("TX: %d samples", dev->tx_len); | |
751 | ||
752 | spin_lock_irqsave(&dev->hw_lock, flags); | |
753 | ||
931e39a1 | 754 | ene_tx_hw_set_transmiter_mask(dev); |
9ea53b74 ML |
755 | ene_tx_prepare(dev); |
756 | ||
757 | /* Transmit first two samples */ | |
758 | ene_tx_sample(dev); | |
759 | ene_tx_sample(dev); | |
760 | ||
761 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
762 | ||
763 | if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) { | |
764 | ene_dbg("TX: timeout"); | |
765 | spin_lock_irqsave(&dev->hw_lock, flags); | |
766 | ene_tx_complete(dev); | |
767 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
768 | } else | |
769 | ene_dbg("TX: done"); | |
9ea53b74 ML |
770 | return n; |
771 | } | |
772 | ||
9ea53b74 | 773 | |
931e39a1 ML |
774 | /* probe entry */ |
775 | static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) | |
9ea53b74 | 776 | { |
9ea53b74 | 777 | int error = -ENOMEM; |
931e39a1 ML |
778 | struct ir_dev_props *ir_props; |
779 | struct input_dev *input_dev; | |
780 | struct ene_device *dev; | |
9ea53b74 | 781 | |
931e39a1 ML |
782 | /* allocate memory */ |
783 | input_dev = input_allocate_device(); | |
784 | ir_props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL); | |
9ea53b74 ML |
785 | dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); |
786 | ||
931e39a1 ML |
787 | if (!input_dev || !ir_props || !dev) |
788 | goto error; | |
9ea53b74 ML |
789 | |
790 | /* validate resources */ | |
931e39a1 ML |
791 | error = -ENODEV; |
792 | ||
9ea53b74 ML |
793 | if (!pnp_port_valid(pnp_dev, 0) || |
794 | pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) | |
931e39a1 | 795 | goto error; |
9ea53b74 ML |
796 | |
797 | if (!pnp_irq_valid(pnp_dev, 0)) | |
931e39a1 | 798 | goto error; |
9ea53b74 ML |
799 | |
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); | |
803 | ||
804 | /* claim the resources */ | |
805 | error = -EBUSY; | |
806 | if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) | |
931e39a1 | 807 | goto error; |
9ea53b74 ML |
808 | |
809 | if (request_irq(dev->irq, ene_isr, | |
810 | IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) | |
931e39a1 ML |
811 | goto error; |
812 | ||
813 | pnp_set_drvdata(pnp_dev, dev); | |
814 | dev->pnp_dev = pnp_dev; | |
9ea53b74 ML |
815 | |
816 | /* detect hardware version and features */ | |
817 | error = ene_hw_detect(dev); | |
818 | if (error) | |
931e39a1 | 819 | goto error; |
9ea53b74 ML |
820 | |
821 | ene_setup_settings(dev); | |
822 | ||
823 | if (!dev->hw_learning_and_tx_capable && txsim) { | |
824 | dev->hw_learning_and_tx_capable = 1; | |
825 | setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, | |
826 | (long unsigned int)dev); | |
827 | ene_printk(KERN_WARNING, | |
828 | "Simulation of TX activated\n"); | |
829 | } | |
830 | ||
931e39a1 ML |
831 | ir_props->driver_type = RC_DRIVER_IR_RAW; |
832 | ir_props->allowed_protos = IR_TYPE_ALL; | |
833 | ir_props->priv = dev; | |
834 | ir_props->open = ene_open; | |
835 | ir_props->close = ene_close; | |
836 | ir_props->min_timeout = ENE_MINGAP * 1000; | |
837 | ir_props->max_timeout = ENE_MAXGAP * 1000; | |
838 | ir_props->timeout = ENE_MAXGAP * 1000; | |
9ea53b74 | 839 | |
931e39a1 ML |
840 | if (dev->hw_revision == ENE_HW_B) |
841 | ir_props->s_idle = ene_rx_set_idle; | |
9ea53b74 | 842 | |
9ea53b74 | 843 | |
931e39a1 ML |
844 | dev->props = ir_props; |
845 | dev->idev = input_dev; | |
9ea53b74 ML |
846 | |
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 | ||
931e39a1 ML |
862 | ir_props->rx_resolution = sample_period * 1000; |
863 | ||
864 | if (dev->hw_learning_and_tx_capable) { | |
865 | ||
866 | 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); | |
872 | ir_props->tx_ir = ene_transmit; | |
873 | ir_props->s_tx_mask = ene_set_tx_mask; | |
874 | ir_props->s_tx_carrier = ene_set_tx_carrier; | |
875 | ir_props->tx_resolution = ENE_TX_SMPL_PERIOD * 1000; | |
876 | /* ir_props->s_carrier_report = ene_set_carrier_report; */ | |
877 | } | |
878 | ||
879 | ||
9ea53b74 ML |
880 | device_set_wakeup_capable(&pnp_dev->dev, 1); |
881 | device_set_wakeup_enable(&pnp_dev->dev, 1); | |
882 | ||
931e39a1 ML |
883 | if (dev->hw_learning_and_tx_capable) |
884 | input_dev->name = "ENE eHome Infrared Remote Transceiver"; | |
885 | else | |
886 | input_dev->name = "ENE eHome Infrared Remote Receiver"; | |
887 | ||
888 | ||
9ea53b74 | 889 | error = -ENODEV; |
931e39a1 ML |
890 | if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props, |
891 | ENE_DRIVER_NAME)) | |
892 | goto error; | |
893 | ||
9ea53b74 ML |
894 | |
895 | ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); | |
896 | return 0; | |
931e39a1 ML |
897 | error: |
898 | if (dev->irq) | |
899 | free_irq(dev->irq, dev); | |
900 | if (dev->hw_io) | |
901 | release_region(dev->hw_io, ENE_MAX_IO); | |
902 | ||
903 | input_free_device(input_dev); | |
904 | kfree(ir_props); | |
9ea53b74 | 905 | kfree(dev); |
9ea53b74 ML |
906 | return error; |
907 | } | |
908 | ||
909 | /* main unload function */ | |
910 | static void ene_remove(struct pnp_dev *pnp_dev) | |
911 | { | |
912 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | |
913 | unsigned long flags; | |
914 | ||
915 | spin_lock_irqsave(&dev->hw_lock, flags); | |
916 | ene_rx_disable(dev); | |
917 | spin_unlock_irqrestore(&dev->hw_lock, flags); | |
918 | ||
919 | free_irq(dev->irq, dev); | |
920 | release_region(dev->hw_io, ENE_MAX_IO); | |
931e39a1 ML |
921 | ir_input_unregister(dev->idev); |
922 | kfree(dev->props); | |
9ea53b74 ML |
923 | kfree(dev); |
924 | } | |
925 | ||
926 | /* enable wake on IR (wakes on specific button on original remote) */ | |
927 | static void ene_enable_wake(struct ene_device *dev, int enable) | |
928 | { | |
929 | enable = enable && device_may_wakeup(&dev->pnp_dev->dev); | |
930 | ||
931 | ene_dbg("wake on IR %s", enable ? "enabled" : "disabled"); | |
932 | ||
933 | ene_hw_write_reg_mask(dev, ENE_FW1, enable ? | |
934 | ENE_FW1_WAKE : 0, ENE_FW1_WAKE); | |
935 | } | |
936 | ||
937 | #ifdef CONFIG_PM | |
938 | static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) | |
939 | { | |
940 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | |
941 | ene_enable_wake(dev, 1); | |
942 | return 0; | |
943 | } | |
944 | ||
945 | static int ene_resume(struct pnp_dev *pnp_dev) | |
946 | { | |
947 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | |
948 | if (dev->in_use) | |
949 | ene_rx_enable(dev); | |
950 | ||
951 | ene_enable_wake(dev, 0); | |
952 | return 0; | |
953 | } | |
954 | #endif | |
955 | ||
956 | static void ene_shutdown(struct pnp_dev *pnp_dev) | |
957 | { | |
958 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | |
959 | ene_enable_wake(dev, 1); | |
960 | } | |
961 | ||
962 | static const struct pnp_device_id ene_ids[] = { | |
963 | {.id = "ENE0100",}, | |
964 | {.id = "ENE0200",}, | |
965 | {.id = "ENE0201",}, | |
931e39a1 | 966 | {.id = "ENE0202",}, |
9ea53b74 ML |
967 | {}, |
968 | }; | |
969 | ||
970 | static struct pnp_driver ene_driver = { | |
971 | .name = ENE_DRIVER_NAME, | |
972 | .id_table = ene_ids, | |
973 | .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, | |
974 | ||
975 | .probe = ene_probe, | |
976 | .remove = __devexit_p(ene_remove), | |
977 | #ifdef CONFIG_PM | |
978 | .suspend = ene_suspend, | |
979 | .resume = ene_resume, | |
980 | #endif | |
981 | .shutdown = ene_shutdown, | |
982 | }; | |
983 | ||
984 | static int __init ene_init(void) | |
985 | { | |
986 | return pnp_register_driver(&ene_driver); | |
987 | } | |
988 | ||
989 | static void ene_exit(void) | |
990 | { | |
991 | pnp_unregister_driver(&ene_driver); | |
992 | } | |
993 | ||
994 | module_param(sample_period, int, S_IRUGO); | |
995 | MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)"); | |
996 | ||
997 | module_param(enable_idle, bool, S_IRUGO | S_IWUSR); | |
998 | MODULE_PARM_DESC(enable_idle, | |
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 | ||
1007 | module_param(debug, int, S_IRUGO | S_IWUSR); | |
1008 | MODULE_PARM_DESC(debug, "Enable debug (debug=2 verbose debug output)"); | |
1009 | ||
1010 | module_param(txsim, bool, S_IRUGO); | |
1011 | MODULE_PARM_DESC(txsim, | |
1012 | "Simulate TX features on unsupported hardware (dangerous)"); | |
1013 | ||
9ea53b74 ML |
1014 | MODULE_DEVICE_TABLE(pnp, ene_ids); |
1015 | MODULE_DESCRIPTION | |
931e39a1 | 1016 | ("Infrared input driver for KB3926B/KB3926C/KB3926D " |
9ea53b74 ML |
1017 | "(aka ENE0100/ENE0200/ENE0201) CIR port"); |
1018 | ||
1019 | MODULE_AUTHOR("Maxim Levitsky"); | |
1020 | MODULE_LICENSE("GPL"); | |
1021 | ||
1022 | module_init(ene_init); | |
1023 | module_exit(ene_exit); |