diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-10 18:09:54 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-10 18:09:54 -0400 |
commit | 7ae0dea900b027cd90e8a3e14deca9a19e17638b (patch) | |
tree | 428cbe411bba90f6580ae21338276c949e91f23a /drivers/staging | |
parent | 6c74700fdb8e3bc34c31790384a8ec16c4fefd97 (diff) | |
parent | 560afa7d85bdfb294506afd3032c315e6827824f (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: (94 commits)
V4L/DVB: tvp7002: fix write to H-PLL Feedback Divider LSB register
V4L/DVB: dvb: siano: free spinlock before schedule()
V4L/DVB: media: video: pvrusb2: remove custom hex_to_bin()
V4L/DVB: drivers: usbvideo: remove custom implementation of hex_to_bin()
V4L/DVB: Report supported QAM modes on bt8xx
V4L/DVB: media: ir-keytable: null dereference in debug code
V4L/DVB: ivtv: convert to the new control framework
V4L/DVB: ivtv: convert gpio subdev to new control framework
V4L/DVB: wm8739: convert to the new control framework
V4L/DVB: cs53l32a: convert to new control framework
V4L/DVB: wm8775: convert to the new control framework
V4L/DVB: cx2341x: convert to the control framework
V4L/DVB: cx25840: convert to the new control framework
V4L/DVB: cx25840/ivtv: replace ugly priv control with s_config
V4L/DVB: saa717x: convert to the new control framework
V4L/DVB: msp3400: convert to the new control framework
V4L/DVB: saa7115: convert to the new control framework
V4L/DVB: v4l2: hook up the new control framework into the core framework
V4L/DVB: Documentation: add v4l2-controls.txt documenting the new controls API
V4L/DVB: v4l2-ctrls: Whitespace cleanups
...
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/lirc/Kconfig | 29 | ||||
-rw-r--r-- | drivers/staging/lirc/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/lirc/lirc_ene0100.c | 646 | ||||
-rw-r--r-- | drivers/staging/lirc/lirc_it87.c | 9 | ||||
-rw-r--r-- | drivers/staging/lirc/lirc_parallel.c | 4 | ||||
-rw-r--r-- | drivers/staging/lirc/lirc_streamzap.c | 821 |
6 files changed, 16 insertions, 1495 deletions
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig index 968c2adee06..100c4d4b812 100644 --- a/drivers/staging/lirc/Kconfig +++ b/drivers/staging/lirc/Kconfig | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | menuconfig LIRC_STAGING | 4 | menuconfig LIRC_STAGING |
5 | bool "Linux Infrared Remote Control IR receiver/transmitter drivers" | 5 | bool "Linux Infrared Remote Control IR receiver/transmitter drivers" |
6 | depends on LIRC | ||
6 | help | 7 | help |
7 | Say Y here, and all supported Linux Infrared Remote Control IR and | 8 | Say Y here, and all supported Linux Infrared Remote Control IR and |
8 | RF receiver and transmitter drivers will be displayed. When paired | 9 | RF receiver and transmitter drivers will be displayed. When paired |
@@ -13,21 +14,13 @@ if LIRC_STAGING | |||
13 | 14 | ||
14 | config LIRC_BT829 | 15 | config LIRC_BT829 |
15 | tristate "BT829 based hardware" | 16 | tristate "BT829 based hardware" |
16 | depends on LIRC_STAGING | 17 | depends on LIRC_STAGING && PCI |
17 | help | 18 | help |
18 | Driver for the IR interface on BT829-based hardware | 19 | Driver for the IR interface on BT829-based hardware |
19 | 20 | ||
20 | config LIRC_ENE0100 | ||
21 | tristate "ENE KB3924/ENE0100 CIR Port Reciever" | ||
22 | depends on LIRC_STAGING | ||
23 | help | ||
24 | This is a driver for CIR port handled by ENE KB3924 embedded | ||
25 | controller found on some notebooks. | ||
26 | It appears on PNP list as ENE0100. | ||
27 | |||
28 | config LIRC_I2C | 21 | config LIRC_I2C |
29 | tristate "I2C Based IR Receivers" | 22 | tristate "I2C Based IR Receivers" |
30 | depends on LIRC_STAGING | 23 | depends on LIRC_STAGING && I2C |
31 | help | 24 | help |
32 | Driver for I2C-based IR receivers, such as those commonly | 25 | Driver for I2C-based IR receivers, such as those commonly |
33 | found onboard Hauppauge PVR-150/250/350 video capture cards | 26 | found onboard Hauppauge PVR-150/250/350 video capture cards |
@@ -40,7 +33,7 @@ config LIRC_IGORPLUGUSB | |||
40 | 33 | ||
41 | config LIRC_IMON | 34 | config LIRC_IMON |
42 | tristate "Legacy SoundGraph iMON Receiver and Display" | 35 | tristate "Legacy SoundGraph iMON Receiver and Display" |
43 | depends on LIRC_STAGING | 36 | depends on LIRC_STAGING && USB |
44 | help | 37 | help |
45 | Driver for the original SoundGraph iMON IR Receiver and Display | 38 | Driver for the original SoundGraph iMON IR Receiver and Display |
46 | 39 | ||
@@ -48,7 +41,7 @@ config LIRC_IMON | |||
48 | 41 | ||
49 | config LIRC_IT87 | 42 | config LIRC_IT87 |
50 | tristate "ITE IT87XX CIR Port Receiver" | 43 | tristate "ITE IT87XX CIR Port Receiver" |
51 | depends on LIRC_STAGING | 44 | depends on LIRC_STAGING && PNP |
52 | help | 45 | help |
53 | Driver for the ITE IT87xx IR Receiver | 46 | Driver for the ITE IT87xx IR Receiver |
54 | 47 | ||
@@ -60,13 +53,13 @@ config LIRC_ITE8709 | |||
60 | 53 | ||
61 | config LIRC_PARALLEL | 54 | config LIRC_PARALLEL |
62 | tristate "Homebrew Parallel Port Receiver" | 55 | tristate "Homebrew Parallel Port Receiver" |
63 | depends on LIRC_STAGING && !SMP | 56 | depends on LIRC_STAGING && PARPORT && !SMP |
64 | help | 57 | help |
65 | Driver for Homebrew Parallel Port Receivers | 58 | Driver for Homebrew Parallel Port Receivers |
66 | 59 | ||
67 | config LIRC_SASEM | 60 | config LIRC_SASEM |
68 | tristate "Sasem USB IR Remote" | 61 | tristate "Sasem USB IR Remote" |
69 | depends on LIRC_STAGING | 62 | depends on LIRC_STAGING && USB |
70 | help | 63 | help |
71 | Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module | 64 | Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module |
72 | 65 | ||
@@ -89,12 +82,6 @@ config LIRC_SIR | |||
89 | help | 82 | help |
90 | Driver for the SIR IrDA port | 83 | Driver for the SIR IrDA port |
91 | 84 | ||
92 | config LIRC_STREAMZAP | ||
93 | tristate "Streamzap PC Receiver" | ||
94 | depends on LIRC_STAGING | ||
95 | help | ||
96 | Driver for the Streamzap PC Receiver | ||
97 | |||
98 | config LIRC_TTUSBIR | 85 | config LIRC_TTUSBIR |
99 | tristate "Technotrend USB IR Receiver" | 86 | tristate "Technotrend USB IR Receiver" |
100 | depends on LIRC_STAGING && USB | 87 | depends on LIRC_STAGING && USB |
@@ -103,7 +90,7 @@ config LIRC_TTUSBIR | |||
103 | 90 | ||
104 | config LIRC_ZILOG | 91 | config LIRC_ZILOG |
105 | tristate "Zilog/Hauppauge IR Transmitter" | 92 | tristate "Zilog/Hauppauge IR Transmitter" |
106 | depends on LIRC_STAGING | 93 | depends on LIRC_STAGING && I2C |
107 | help | 94 | help |
108 | Driver for the Zilog/Hauppauge IR Transmitter, found on | 95 | Driver for the Zilog/Hauppauge IR Transmitter, found on |
109 | PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards | 96 | PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards |
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile index a019182a7a3..4da1f3397a1 100644 --- a/drivers/staging/lirc/Makefile +++ b/drivers/staging/lirc/Makefile | |||
@@ -4,7 +4,6 @@ | |||
4 | # Each configuration option enables a list of files. | 4 | # Each configuration option enables a list of files. |
5 | 5 | ||
6 | obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o | 6 | obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o |
7 | obj-$(CONFIG_LIRC_ENE0100) += lirc_ene0100.o | ||
8 | obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o | 7 | obj-$(CONFIG_LIRC_I2C) += lirc_i2c.o |
9 | obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o | 8 | obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o |
10 | obj-$(CONFIG_LIRC_IMON) += lirc_imon.o | 9 | obj-$(CONFIG_LIRC_IMON) += lirc_imon.o |
@@ -14,6 +13,5 @@ obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o | |||
14 | obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o | 13 | obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o |
15 | obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o | 14 | obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o |
16 | obj-$(CONFIG_LIRC_SIR) += lirc_sir.o | 15 | obj-$(CONFIG_LIRC_SIR) += lirc_sir.o |
17 | obj-$(CONFIG_LIRC_STREAMZAP) += lirc_streamzap.o | ||
18 | obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o | 16 | obj-$(CONFIG_LIRC_TTUSBIR) += lirc_ttusbir.o |
19 | obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o | 17 | obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o |
diff --git a/drivers/staging/lirc/lirc_ene0100.c b/drivers/staging/lirc/lirc_ene0100.c deleted file mode 100644 index a152c52b074..00000000000 --- a/drivers/staging/lirc/lirc_ene0100.c +++ /dev/null | |||
@@ -1,646 +0,0 @@ | |||
1 | /* | ||
2 | * driver for ENE KB3926 B/C/D CIR (also known as ENE0100) | ||
3 | * | ||
4 | * Copyright (C) 2009 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> | ||
28 | #include "lirc_ene0100.h" | ||
29 | |||
30 | static int sample_period = 75; | ||
31 | static int enable_idle = 1; | ||
32 | static int enable_learning; | ||
33 | |||
34 | static void ene_set_idle(struct ene_device *dev, int idle); | ||
35 | static void ene_set_inputs(struct ene_device *dev, int enable); | ||
36 | |||
37 | /* read a hardware register */ | ||
38 | static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg) | ||
39 | { | ||
40 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | ||
41 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | ||
42 | return inb(dev->hw_io + ENE_IO); | ||
43 | } | ||
44 | |||
45 | /* write a hardware register */ | ||
46 | static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value) | ||
47 | { | ||
48 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | ||
49 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | ||
50 | outb(value, dev->hw_io + ENE_IO); | ||
51 | } | ||
52 | |||
53 | /* change specific bits in hardware register */ | ||
54 | static void ene_hw_write_reg_mask(struct ene_device *dev, | ||
55 | u16 reg, u8 value, u8 mask) | ||
56 | { | ||
57 | u8 regvalue; | ||
58 | |||
59 | outb(reg >> 8, dev->hw_io + ENE_ADDR_HI); | ||
60 | outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO); | ||
61 | |||
62 | regvalue = inb(dev->hw_io + ENE_IO) & ~mask; | ||
63 | regvalue |= (value & mask); | ||
64 | outb(regvalue, dev->hw_io + ENE_IO); | ||
65 | } | ||
66 | |||
67 | /* read irq status and ack it */ | ||
68 | static int ene_hw_irq_status(struct ene_device *dev, int *buffer_pointer) | ||
69 | { | ||
70 | u8 irq_status; | ||
71 | u8 fw_flags1, fw_flags2; | ||
72 | |||
73 | fw_flags2 = ene_hw_read_reg(dev, ENE_FW2); | ||
74 | |||
75 | if (buffer_pointer) | ||
76 | *buffer_pointer = 4 * (fw_flags2 & ENE_FW2_BUF_HIGH); | ||
77 | |||
78 | if (dev->hw_revision < ENE_HW_C) { | ||
79 | irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS); | ||
80 | |||
81 | if (!(irq_status & ENEB_IRQ_STATUS_IR)) | ||
82 | return 0; | ||
83 | ene_hw_write_reg(dev, ENEB_IRQ_STATUS, | ||
84 | irq_status & ~ENEB_IRQ_STATUS_IR); | ||
85 | |||
86 | /* rev B support only recieving */ | ||
87 | return ENE_IRQ_RX; | ||
88 | } | ||
89 | |||
90 | irq_status = ene_hw_read_reg(dev, ENEC_IRQ); | ||
91 | |||
92 | if (!(irq_status & ENEC_IRQ_STATUS)) | ||
93 | return 0; | ||
94 | |||
95 | /* original driver does that twice - a workaround ? */ | ||
96 | ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); | ||
97 | ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS); | ||
98 | |||
99 | /* clear unknown flag in F8F9 */ | ||
100 | if (fw_flags2 & ENE_FW2_IRQ_CLR) | ||
101 | ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR); | ||
102 | |||
103 | /* check if this is a TX interrupt */ | ||
104 | fw_flags1 = ene_hw_read_reg(dev, ENE_FW1); | ||
105 | |||
106 | if (fw_flags1 & ENE_FW1_TXIRQ) { | ||
107 | ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ); | ||
108 | return ENE_IRQ_TX; | ||
109 | } else | ||
110 | return ENE_IRQ_RX; | ||
111 | } | ||
112 | |||
113 | static int ene_hw_detect(struct ene_device *dev) | ||
114 | { | ||
115 | u8 chip_major, chip_minor; | ||
116 | u8 hw_revision, old_ver; | ||
117 | u8 tmp; | ||
118 | u8 fw_capabilities; | ||
119 | |||
120 | tmp = ene_hw_read_reg(dev, ENE_HW_UNK); | ||
121 | ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR); | ||
122 | |||
123 | chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR); | ||
124 | chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR); | ||
125 | |||
126 | ene_hw_write_reg(dev, ENE_HW_UNK, tmp); | ||
127 | hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION); | ||
128 | old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD); | ||
129 | |||
130 | if (hw_revision == 0xFF) { | ||
131 | |||
132 | ene_printk(KERN_WARNING, "device seems to be disabled\n"); | ||
133 | ene_printk(KERN_WARNING, | ||
134 | "send a mail to lirc-list@lists.sourceforge.net\n"); | ||
135 | ene_printk(KERN_WARNING, "please attach output of acpidump\n"); | ||
136 | |||
137 | return -ENODEV; | ||
138 | } | ||
139 | |||
140 | if (chip_major == 0x33) { | ||
141 | ene_printk(KERN_WARNING, "chips 0x33xx aren't supported yet\n"); | ||
142 | return -ENODEV; | ||
143 | } | ||
144 | |||
145 | if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) { | ||
146 | dev->hw_revision = ENE_HW_C; | ||
147 | ene_printk(KERN_WARNING, | ||
148 | "KB3926C detected, driver support is not complete!\n"); | ||
149 | |||
150 | } else if (old_ver == 0x24 && hw_revision == 0xC0) { | ||
151 | dev->hw_revision = ENE_HW_B; | ||
152 | ene_printk(KERN_NOTICE, "KB3926B detected\n"); | ||
153 | } else { | ||
154 | dev->hw_revision = ENE_HW_D; | ||
155 | ene_printk(KERN_WARNING, | ||
156 | "unknown ENE chip detected, assuming KB3926D\n"); | ||
157 | ene_printk(KERN_WARNING, "driver support incomplete"); | ||
158 | |||
159 | } | ||
160 | |||
161 | ene_printk(KERN_DEBUG, "chip is 0x%02x%02x - 0x%02x, 0x%02x\n", | ||
162 | chip_major, chip_minor, old_ver, hw_revision); | ||
163 | |||
164 | |||
165 | /* detect features hardware supports */ | ||
166 | |||
167 | if (dev->hw_revision < ENE_HW_C) | ||
168 | return 0; | ||
169 | |||
170 | fw_capabilities = ene_hw_read_reg(dev, ENE_FW2); | ||
171 | |||
172 | dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN; | ||
173 | dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING; | ||
174 | |||
175 | dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable && | ||
176 | fw_capabilities & ENE_FW2_FAN_AS_NRML_IN; | ||
177 | |||
178 | ene_printk(KERN_NOTICE, "hardware features:\n"); | ||
179 | ene_printk(KERN_NOTICE, | ||
180 | "learning and tx %s, gpio40_learn %s, fan_in %s\n", | ||
181 | dev->hw_learning_and_tx_capable ? "on" : "off", | ||
182 | dev->hw_gpio40_learning ? "on" : "off", | ||
183 | dev->hw_fan_as_normal_input ? "on" : "off"); | ||
184 | |||
185 | if (!dev->hw_learning_and_tx_capable && enable_learning) | ||
186 | enable_learning = 0; | ||
187 | |||
188 | if (dev->hw_learning_and_tx_capable) { | ||
189 | ene_printk(KERN_WARNING, | ||
190 | "Device supports transmitting, but the driver doesn't\n"); | ||
191 | ene_printk(KERN_WARNING, | ||
192 | "due to lack of hardware to test against.\n"); | ||
193 | ene_printk(KERN_WARNING, | ||
194 | "Send a mail to: lirc-list@lists.sourceforge.net\n"); | ||
195 | } | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | /* hardware initialization */ | ||
200 | static int ene_hw_init(void *data) | ||
201 | { | ||
202 | u8 reg_value; | ||
203 | struct ene_device *dev = (struct ene_device *)data; | ||
204 | dev->in_use = 1; | ||
205 | |||
206 | if (dev->hw_revision < ENE_HW_C) { | ||
207 | ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1); | ||
208 | ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01); | ||
209 | } else { | ||
210 | reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0; | ||
211 | reg_value |= ENEC_IRQ_UNK_EN; | ||
212 | reg_value &= ~ENEC_IRQ_STATUS; | ||
213 | reg_value |= (dev->irq & ENEC_IRQ_MASK); | ||
214 | ene_hw_write_reg(dev, ENEC_IRQ, reg_value); | ||
215 | ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63); | ||
216 | } | ||
217 | |||
218 | ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00); | ||
219 | ene_set_inputs(dev, enable_learning); | ||
220 | |||
221 | /* set sampling period */ | ||
222 | ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period); | ||
223 | |||
224 | /* ack any pending irqs - just in case */ | ||
225 | ene_hw_irq_status(dev, NULL); | ||
226 | |||
227 | /* enter idle mode */ | ||
228 | ene_set_idle(dev, 1); | ||
229 | |||
230 | /* enable firmware bits */ | ||
231 | ene_hw_write_reg_mask(dev, ENE_FW1, | ||
232 | ENE_FW1_ENABLE | ENE_FW1_IRQ, | ||
233 | ENE_FW1_ENABLE | ENE_FW1_IRQ); | ||
234 | /* clear stats */ | ||
235 | dev->sample = 0; | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | /* this enables gpio40 signal, used if connected to wide band input*/ | ||
240 | static void ene_enable_gpio40(struct ene_device *dev, int enable) | ||
241 | { | ||
242 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, enable ? | ||
243 | 0 : ENE_CIR_CONF2_GPIO40DIS, | ||
244 | ENE_CIR_CONF2_GPIO40DIS); | ||
245 | } | ||
246 | |||
247 | /* this enables the classic sampler */ | ||
248 | static void ene_enable_normal_recieve(struct ene_device *dev, int enable) | ||
249 | { | ||
250 | ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_ADC_ON : 0); | ||
251 | } | ||
252 | |||
253 | /* this enables recieve via fan input */ | ||
254 | static void ene_enable_fan_recieve(struct ene_device *dev, int enable) | ||
255 | { | ||
256 | if (!enable) | ||
257 | ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0); | ||
258 | else { | ||
259 | ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN); | ||
260 | ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN); | ||
261 | } | ||
262 | dev->fan_input_inuse = enable; | ||
263 | } | ||
264 | |||
265 | /* determine which input to use*/ | ||
266 | static void ene_set_inputs(struct ene_device *dev, int learning_enable) | ||
267 | { | ||
268 | ene_enable_normal_recieve(dev, 1); | ||
269 | |||
270 | /* old hardware doesn't support learning mode for sure */ | ||
271 | if (dev->hw_revision <= ENE_HW_B) | ||
272 | return; | ||
273 | |||
274 | /* reciever not learning capable, still set gpio40 correctly */ | ||
275 | if (!dev->hw_learning_and_tx_capable) { | ||
276 | ene_enable_gpio40(dev, !dev->hw_gpio40_learning); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | /* enable learning mode */ | ||
281 | if (learning_enable) { | ||
282 | ene_enable_gpio40(dev, dev->hw_gpio40_learning); | ||
283 | |||
284 | /* fan input is not used for learning */ | ||
285 | if (dev->hw_fan_as_normal_input) | ||
286 | ene_enable_fan_recieve(dev, 0); | ||
287 | |||
288 | /* disable learning mode */ | ||
289 | } else { | ||
290 | if (dev->hw_fan_as_normal_input) { | ||
291 | ene_enable_fan_recieve(dev, 1); | ||
292 | ene_enable_normal_recieve(dev, 0); | ||
293 | } else | ||
294 | ene_enable_gpio40(dev, !dev->hw_gpio40_learning); | ||
295 | } | ||
296 | |||
297 | /* set few additional settings for this mode */ | ||
298 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_enable ? | ||
299 | ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1); | ||
300 | |||
301 | ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_enable ? | ||
302 | ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2); | ||
303 | } | ||
304 | |||
305 | /* deinitialization */ | ||
306 | static void ene_hw_deinit(void *data) | ||
307 | { | ||
308 | struct ene_device *dev = (struct ene_device *)data; | ||
309 | |||
310 | /* disable samplers */ | ||
311 | ene_enable_normal_recieve(dev, 0); | ||
312 | |||
313 | if (dev->hw_fan_as_normal_input) | ||
314 | ene_enable_fan_recieve(dev, 0); | ||
315 | |||
316 | /* disable hardware IRQ and firmware flag */ | ||
317 | ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ); | ||
318 | |||
319 | ene_set_idle(dev, 1); | ||
320 | dev->in_use = 0; | ||
321 | } | ||
322 | |||
323 | /* sends current sample to userspace */ | ||
324 | static void send_sample(struct ene_device *dev) | ||
325 | { | ||
326 | int value = abs(dev->sample) & PULSE_MASK; | ||
327 | |||
328 | if (dev->sample > 0) | ||
329 | value |= PULSE_BIT; | ||
330 | |||
331 | if (!lirc_buffer_full(dev->lirc_driver->rbuf)) { | ||
332 | lirc_buffer_write(dev->lirc_driver->rbuf, (void *)&value); | ||
333 | wake_up(&dev->lirc_driver->rbuf->wait_poll); | ||
334 | } | ||
335 | dev->sample = 0; | ||
336 | } | ||
337 | |||
338 | /* this updates current sample */ | ||
339 | static void update_sample(struct ene_device *dev, int sample) | ||
340 | { | ||
341 | if (!dev->sample) | ||
342 | dev->sample = sample; | ||
343 | else if (same_sign(dev->sample, sample)) | ||
344 | dev->sample += sample; | ||
345 | else { | ||
346 | send_sample(dev); | ||
347 | dev->sample = sample; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | /* enable or disable idle mode */ | ||
352 | static void ene_set_idle(struct ene_device *dev, int idle) | ||
353 | { | ||
354 | struct timeval now; | ||
355 | int disable = idle && enable_idle && (dev->hw_revision < ENE_HW_C); | ||
356 | |||
357 | ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD, | ||
358 | disable ? 0 : ENE_CIR_SAMPLE_OVERFLOW, | ||
359 | ENE_CIR_SAMPLE_OVERFLOW); | ||
360 | dev->idle = idle; | ||
361 | |||
362 | /* remember when we have entered the idle mode */ | ||
363 | if (idle) { | ||
364 | do_gettimeofday(&dev->gap_start); | ||
365 | return; | ||
366 | } | ||
367 | |||
368 | /* send the gap between keypresses now */ | ||
369 | do_gettimeofday(&now); | ||
370 | |||
371 | if (now.tv_sec - dev->gap_start.tv_sec > 16) | ||
372 | dev->sample = space(PULSE_MASK); | ||
373 | else | ||
374 | dev->sample = dev->sample + | ||
375 | space(1000000ull * (now.tv_sec - dev->gap_start.tv_sec)) | ||
376 | + space(now.tv_usec - dev->gap_start.tv_usec); | ||
377 | |||
378 | if (abs(dev->sample) > PULSE_MASK) | ||
379 | dev->sample = space(PULSE_MASK); | ||
380 | send_sample(dev); | ||
381 | } | ||
382 | |||
383 | /* interrupt handler */ | ||
384 | static irqreturn_t ene_hw_irq(int irq, void *data) | ||
385 | { | ||
386 | u16 hw_value; | ||
387 | int i, hw_sample; | ||
388 | int space; | ||
389 | int buffer_pointer; | ||
390 | int irq_status; | ||
391 | |||
392 | struct ene_device *dev = (struct ene_device *)data; | ||
393 | irq_status = ene_hw_irq_status(dev, &buffer_pointer); | ||
394 | |||
395 | if (!irq_status) | ||
396 | return IRQ_NONE; | ||
397 | |||
398 | /* TODO: only RX for now */ | ||
399 | if (irq_status == ENE_IRQ_TX) | ||
400 | return IRQ_HANDLED; | ||
401 | |||
402 | for (i = 0; i < ENE_SAMPLES_SIZE; i++) { | ||
403 | |||
404 | hw_value = ene_hw_read_reg(dev, | ||
405 | ENE_SAMPLE_BUFFER + buffer_pointer + i); | ||
406 | |||
407 | if (dev->fan_input_inuse) { | ||
408 | /* read high part of the sample */ | ||
409 | hw_value |= ene_hw_read_reg(dev, | ||
410 | ENE_SAMPLE_BUFFER_FAN + buffer_pointer + i) << 8; | ||
411 | |||
412 | /* test for _space_ bit */ | ||
413 | space = !(hw_value & ENE_FAN_SMPL_PULS_MSK); | ||
414 | |||
415 | /* clear space bit, and other unused bits */ | ||
416 | hw_value &= ENE_FAN_VALUE_MASK; | ||
417 | hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN; | ||
418 | |||
419 | } else { | ||
420 | space = hw_value & ENE_SAMPLE_SPC_MASK; | ||
421 | hw_value &= ENE_SAMPLE_VALUE_MASK; | ||
422 | hw_sample = hw_value * sample_period; | ||
423 | } | ||
424 | |||
425 | /* no more data */ | ||
426 | if (!(hw_value)) | ||
427 | break; | ||
428 | |||
429 | if (space) | ||
430 | hw_sample *= -1; | ||
431 | |||
432 | /* overflow sample recieved, handle it */ | ||
433 | |||
434 | if (!dev->fan_input_inuse && hw_value == ENE_SAMPLE_OVERFLOW) { | ||
435 | |||
436 | if (dev->idle) | ||
437 | continue; | ||
438 | |||
439 | if (dev->sample > 0 || abs(dev->sample) <= ENE_MAXGAP) | ||
440 | update_sample(dev, hw_sample); | ||
441 | else | ||
442 | ene_set_idle(dev, 1); | ||
443 | |||
444 | continue; | ||
445 | } | ||
446 | |||
447 | /* normal first sample recieved */ | ||
448 | if (!dev->fan_input_inuse && dev->idle) { | ||
449 | ene_set_idle(dev, 0); | ||
450 | |||
451 | /* discard first recieved value, its random | ||
452 | since its the time signal was off before | ||
453 | first pulse if idle mode is enabled, HW | ||
454 | does that for us */ | ||
455 | |||
456 | if (!enable_idle) | ||
457 | continue; | ||
458 | } | ||
459 | update_sample(dev, hw_sample); | ||
460 | send_sample(dev); | ||
461 | } | ||
462 | return IRQ_HANDLED; | ||
463 | } | ||
464 | |||
465 | static int ene_probe(struct pnp_dev *pnp_dev, | ||
466 | const struct pnp_device_id *dev_id) | ||
467 | { | ||
468 | struct ene_device *dev; | ||
469 | struct lirc_driver *lirc_driver; | ||
470 | int error = -ENOMEM; | ||
471 | |||
472 | dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); | ||
473 | |||
474 | if (!dev) | ||
475 | goto err1; | ||
476 | |||
477 | dev->pnp_dev = pnp_dev; | ||
478 | pnp_set_drvdata(pnp_dev, dev); | ||
479 | |||
480 | |||
481 | /* prepare lirc interface */ | ||
482 | error = -ENOMEM; | ||
483 | lirc_driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); | ||
484 | |||
485 | if (!lirc_driver) | ||
486 | goto err2; | ||
487 | |||
488 | dev->lirc_driver = lirc_driver; | ||
489 | |||
490 | strcpy(lirc_driver->name, ENE_DRIVER_NAME); | ||
491 | lirc_driver->minor = -1; | ||
492 | lirc_driver->code_length = sizeof(int) * 8; | ||
493 | lirc_driver->features = LIRC_CAN_REC_MODE2; | ||
494 | lirc_driver->data = dev; | ||
495 | lirc_driver->set_use_inc = ene_hw_init; | ||
496 | lirc_driver->set_use_dec = ene_hw_deinit; | ||
497 | lirc_driver->dev = &pnp_dev->dev; | ||
498 | lirc_driver->owner = THIS_MODULE; | ||
499 | |||
500 | lirc_driver->rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL); | ||
501 | |||
502 | if (!lirc_driver->rbuf) | ||
503 | goto err3; | ||
504 | |||
505 | if (lirc_buffer_init(lirc_driver->rbuf, sizeof(int), sizeof(int) * 256)) | ||
506 | goto err4; | ||
507 | |||
508 | error = -ENODEV; | ||
509 | if (lirc_register_driver(lirc_driver)) | ||
510 | goto err5; | ||
511 | |||
512 | /* validate resources */ | ||
513 | if (!pnp_port_valid(pnp_dev, 0) || | ||
514 | pnp_port_len(pnp_dev, 0) < ENE_MAX_IO) | ||
515 | goto err6; | ||
516 | |||
517 | if (!pnp_irq_valid(pnp_dev, 0)) | ||
518 | goto err6; | ||
519 | |||
520 | dev->hw_io = pnp_port_start(pnp_dev, 0); | ||
521 | dev->irq = pnp_irq(pnp_dev, 0); | ||
522 | |||
523 | /* claim the resources */ | ||
524 | error = -EBUSY; | ||
525 | if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME)) | ||
526 | goto err6; | ||
527 | |||
528 | if (request_irq(dev->irq, ene_hw_irq, | ||
529 | IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) | ||
530 | goto err7; | ||
531 | |||
532 | /* detect hardware version and features */ | ||
533 | error = ene_hw_detect(dev); | ||
534 | if (error) | ||
535 | goto err8; | ||
536 | |||
537 | ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n"); | ||
538 | return 0; | ||
539 | |||
540 | err8: | ||
541 | free_irq(dev->irq, dev); | ||
542 | err7: | ||
543 | release_region(dev->hw_io, ENE_MAX_IO); | ||
544 | err6: | ||
545 | lirc_unregister_driver(lirc_driver->minor); | ||
546 | err5: | ||
547 | lirc_buffer_free(lirc_driver->rbuf); | ||
548 | err4: | ||
549 | kfree(lirc_driver->rbuf); | ||
550 | err3: | ||
551 | kfree(lirc_driver); | ||
552 | err2: | ||
553 | kfree(dev); | ||
554 | err1: | ||
555 | return error; | ||
556 | } | ||
557 | |||
558 | static void ene_remove(struct pnp_dev *pnp_dev) | ||
559 | { | ||
560 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | ||
561 | ene_hw_deinit(dev); | ||
562 | free_irq(dev->irq, dev); | ||
563 | release_region(dev->hw_io, ENE_MAX_IO); | ||
564 | lirc_unregister_driver(dev->lirc_driver->minor); | ||
565 | lirc_buffer_free(dev->lirc_driver->rbuf); | ||
566 | kfree(dev->lirc_driver); | ||
567 | kfree(dev); | ||
568 | } | ||
569 | |||
570 | #ifdef CONFIG_PM | ||
571 | |||
572 | /* TODO: make 'wake on IR' configurable and add .shutdown */ | ||
573 | /* currently impossible due to lack of kernel support */ | ||
574 | |||
575 | static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state) | ||
576 | { | ||
577 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | ||
578 | ene_hw_write_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, ENE_FW1_WAKE); | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int ene_resume(struct pnp_dev *pnp_dev) | ||
583 | { | ||
584 | struct ene_device *dev = pnp_get_drvdata(pnp_dev); | ||
585 | if (dev->in_use) | ||
586 | ene_hw_init(dev); | ||
587 | |||
588 | ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_WAKE); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | #endif | ||
593 | |||
594 | static const struct pnp_device_id ene_ids[] = { | ||
595 | {.id = "ENE0100",}, | ||
596 | {}, | ||
597 | }; | ||
598 | |||
599 | static struct pnp_driver ene_driver = { | ||
600 | .name = ENE_DRIVER_NAME, | ||
601 | .id_table = ene_ids, | ||
602 | .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, | ||
603 | |||
604 | .probe = ene_probe, | ||
605 | .remove = __devexit_p(ene_remove), | ||
606 | |||
607 | #ifdef CONFIG_PM | ||
608 | .suspend = ene_suspend, | ||
609 | .resume = ene_resume, | ||
610 | #endif | ||
611 | }; | ||
612 | |||
613 | static int __init ene_init(void) | ||
614 | { | ||
615 | if (sample_period < 5) { | ||
616 | ene_printk(KERN_ERR, "sample period must be at\n"); | ||
617 | ene_printk(KERN_ERR, "least 5 us, (at least 30 recommended)\n"); | ||
618 | return -EINVAL; | ||
619 | } | ||
620 | return pnp_register_driver(&ene_driver); | ||
621 | } | ||
622 | |||
623 | static void ene_exit(void) | ||
624 | { | ||
625 | pnp_unregister_driver(&ene_driver); | ||
626 | } | ||
627 | |||
628 | module_param(sample_period, int, S_IRUGO); | ||
629 | MODULE_PARM_DESC(sample_period, "Hardware sample period (75 us default)"); | ||
630 | |||
631 | module_param(enable_idle, bool, S_IRUGO | S_IWUSR); | ||
632 | MODULE_PARM_DESC(enable_idle, | ||
633 | "Enables turning off signal sampling after long inactivity time; " | ||
634 | "if disabled might help detecting input signal (default: enabled)"); | ||
635 | |||
636 | module_param(enable_learning, bool, S_IRUGO); | ||
637 | MODULE_PARM_DESC(enable_learning, "Use wide band (learning) reciever"); | ||
638 | |||
639 | MODULE_DEVICE_TABLE(pnp, ene_ids); | ||
640 | MODULE_DESCRIPTION | ||
641 | ("LIRC driver for KB3926B/KB3926C/KB3926D (aka ENE0100) CIR port"); | ||
642 | MODULE_AUTHOR("Maxim Levitsky"); | ||
643 | MODULE_LICENSE("GPL"); | ||
644 | |||
645 | module_init(ene_init); | ||
646 | module_exit(ene_exit); | ||
diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c index 09f36961c6d..ec11c0e949a 100644 --- a/drivers/staging/lirc/lirc_it87.c +++ b/drivers/staging/lirc/lirc_it87.c | |||
@@ -109,6 +109,7 @@ static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); | |||
109 | 109 | ||
110 | static DEFINE_SPINLOCK(hardware_lock); | 110 | static DEFINE_SPINLOCK(hardware_lock); |
111 | static DEFINE_SPINLOCK(dev_lock); | 111 | static DEFINE_SPINLOCK(dev_lock); |
112 | static bool device_open; | ||
112 | 113 | ||
113 | static int rx_buf[RBUF_LEN]; | 114 | static int rx_buf[RBUF_LEN]; |
114 | unsigned int rx_tail, rx_head; | 115 | unsigned int rx_tail, rx_head; |
@@ -147,10 +148,11 @@ static void drop_port(void); | |||
147 | static int lirc_open(struct inode *inode, struct file *file) | 148 | static int lirc_open(struct inode *inode, struct file *file) |
148 | { | 149 | { |
149 | spin_lock(&dev_lock); | 150 | spin_lock(&dev_lock); |
150 | if (module_refcount(THIS_MODULE)) { | 151 | if (device_open) { |
151 | spin_unlock(&dev_lock); | 152 | spin_unlock(&dev_lock); |
152 | return -EBUSY; | 153 | return -EBUSY; |
153 | } | 154 | } |
155 | device_open = true; | ||
154 | spin_unlock(&dev_lock); | 156 | spin_unlock(&dev_lock); |
155 | return 0; | 157 | return 0; |
156 | } | 158 | } |
@@ -158,6 +160,9 @@ static int lirc_open(struct inode *inode, struct file *file) | |||
158 | 160 | ||
159 | static int lirc_close(struct inode *inode, struct file *file) | 161 | static int lirc_close(struct inode *inode, struct file *file) |
160 | { | 162 | { |
163 | spin_lock(&dev_lock); | ||
164 | device_open = false; | ||
165 | spin_unlock(&dev_lock); | ||
161 | return 0; | 166 | return 0; |
162 | } | 167 | } |
163 | 168 | ||
@@ -363,7 +368,6 @@ static struct lirc_driver driver = { | |||
363 | }; | 368 | }; |
364 | 369 | ||
365 | 370 | ||
366 | #ifdef MODULE | ||
367 | static int init_chrdev(void) | 371 | static int init_chrdev(void) |
368 | { | 372 | { |
369 | driver.minor = lirc_register_driver(&driver); | 373 | driver.minor = lirc_register_driver(&driver); |
@@ -380,7 +384,6 @@ static void drop_chrdev(void) | |||
380 | { | 384 | { |
381 | lirc_unregister_driver(driver.minor); | 385 | lirc_unregister_driver(driver.minor); |
382 | } | 386 | } |
383 | #endif | ||
384 | 387 | ||
385 | 388 | ||
386 | /* SECTION: Hardware */ | 389 | /* SECTION: Hardware */ |
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c index a1ebd071640..6da4a8c6ebc 100644 --- a/drivers/staging/lirc/lirc_parallel.c +++ b/drivers/staging/lirc/lirc_parallel.c | |||
@@ -240,7 +240,7 @@ static void irq_handler(void *blah) | |||
240 | unsigned int level, newlevel; | 240 | unsigned int level, newlevel; |
241 | unsigned int timeout; | 241 | unsigned int timeout; |
242 | 242 | ||
243 | if (!module_refcount(THIS_MODULE)) | 243 | if (!is_open) |
244 | return; | 244 | return; |
245 | 245 | ||
246 | if (!is_claimed) | 246 | if (!is_claimed) |
@@ -515,7 +515,7 @@ static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) | |||
515 | 515 | ||
516 | static int lirc_open(struct inode *node, struct file *filep) | 516 | static int lirc_open(struct inode *node, struct file *filep) |
517 | { | 517 | { |
518 | if (module_refcount(THIS_MODULE) || !lirc_claim()) | 518 | if (is_open || !lirc_claim()) |
519 | return -EBUSY; | 519 | return -EBUSY; |
520 | 520 | ||
521 | parport_enable_irq(pport); | 521 | parport_enable_irq(pport); |
diff --git a/drivers/staging/lirc/lirc_streamzap.c b/drivers/staging/lirc/lirc_streamzap.c deleted file mode 100644 index be09c103f0c..00000000000 --- a/drivers/staging/lirc/lirc_streamzap.c +++ /dev/null | |||
@@ -1,821 +0,0 @@ | |||
1 | /* | ||
2 | * Streamzap Remote Control driver | ||
3 | * | ||
4 | * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de> | ||
5 | * | ||
6 | * This driver was based on the work of Greg Wickham and Adrian | ||
7 | * Dewhurst. It was substantially rewritten to support correct signal | ||
8 | * gaps and now maintains a delay buffer, which is used to present | ||
9 | * consistent timing behaviour to user space applications. Without the | ||
10 | * delay buffer an ugly hack would be required in lircd, which can | ||
11 | * cause sluggish signal decoding in certain situations. | ||
12 | * | ||
13 | * This driver is based on the USB skeleton driver packaged with the | ||
14 | * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com) | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | */ | ||
30 | |||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/smp_lock.h> | ||
37 | #include <linux/completion.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | #include <linux/usb.h> | ||
40 | |||
41 | #include <media/lirc.h> | ||
42 | #include <media/lirc_dev.h> | ||
43 | |||
44 | #define DRIVER_VERSION "1.28" | ||
45 | #define DRIVER_NAME "lirc_streamzap" | ||
46 | #define DRIVER_DESC "Streamzap Remote Control driver" | ||
47 | |||
48 | static int debug; | ||
49 | |||
50 | #define USB_STREAMZAP_VENDOR_ID 0x0e9c | ||
51 | #define USB_STREAMZAP_PRODUCT_ID 0x0000 | ||
52 | |||
53 | /* Use our own dbg macro */ | ||
54 | #define dprintk(fmt, args...) \ | ||
55 | do { \ | ||
56 | if (debug) \ | ||
57 | printk(KERN_DEBUG DRIVER_NAME "[%d]: " \ | ||
58 | fmt "\n", ## args); \ | ||
59 | } while (0) | ||
60 | |||
61 | /* table of devices that work with this driver */ | ||
62 | static struct usb_device_id streamzap_table[] = { | ||
63 | /* Streamzap Remote Control */ | ||
64 | { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, | ||
65 | /* Terminating entry */ | ||
66 | { } | ||
67 | }; | ||
68 | |||
69 | MODULE_DEVICE_TABLE(usb, streamzap_table); | ||
70 | |||
71 | #define STREAMZAP_PULSE_MASK 0xf0 | ||
72 | #define STREAMZAP_SPACE_MASK 0x0f | ||
73 | #define STREAMZAP_TIMEOUT 0xff | ||
74 | #define STREAMZAP_RESOLUTION 256 | ||
75 | |||
76 | /* number of samples buffered */ | ||
77 | #define STREAMZAP_BUF_LEN 128 | ||
78 | |||
79 | enum StreamzapDecoderState { | ||
80 | PulseSpace, | ||
81 | FullPulse, | ||
82 | FullSpace, | ||
83 | IgnorePulse | ||
84 | }; | ||
85 | |||
86 | /* Structure to hold all of our device specific stuff | ||
87 | * | ||
88 | * some remarks regarding locking: | ||
89 | * theoretically this struct can be accessed from three threads: | ||
90 | * | ||
91 | * - from lirc_dev through set_use_inc/set_use_dec | ||
92 | * | ||
93 | * - from the USB layer throuh probe/disconnect/irq | ||
94 | * | ||
95 | * Careful placement of lirc_register_driver/lirc_unregister_driver | ||
96 | * calls will prevent conflicts. lirc_dev makes sure that | ||
97 | * set_use_inc/set_use_dec are not being executed and will not be | ||
98 | * called after lirc_unregister_driver returns. | ||
99 | * | ||
100 | * - by the timer callback | ||
101 | * | ||
102 | * The timer is only running when the device is connected and the | ||
103 | * LIRC device is open. Making sure the timer is deleted by | ||
104 | * set_use_dec will make conflicts impossible. | ||
105 | */ | ||
106 | struct usb_streamzap { | ||
107 | |||
108 | /* usb */ | ||
109 | /* save off the usb device pointer */ | ||
110 | struct usb_device *udev; | ||
111 | /* the interface for this device */ | ||
112 | struct usb_interface *interface; | ||
113 | |||
114 | /* buffer & dma */ | ||
115 | unsigned char *buf_in; | ||
116 | dma_addr_t dma_in; | ||
117 | unsigned int buf_in_len; | ||
118 | |||
119 | struct usb_endpoint_descriptor *endpoint; | ||
120 | |||
121 | /* IRQ */ | ||
122 | struct urb *urb_in; | ||
123 | |||
124 | /* lirc */ | ||
125 | struct lirc_driver *driver; | ||
126 | struct lirc_buffer *delay_buf; | ||
127 | |||
128 | /* timer used to support delay buffering */ | ||
129 | struct timer_list delay_timer; | ||
130 | int timer_running; | ||
131 | spinlock_t timer_lock; | ||
132 | |||
133 | /* tracks whether we are currently receiving some signal */ | ||
134 | int idle; | ||
135 | /* sum of signal lengths received since signal start */ | ||
136 | unsigned long sum; | ||
137 | /* start time of signal; necessary for gap tracking */ | ||
138 | struct timeval signal_last; | ||
139 | struct timeval signal_start; | ||
140 | enum StreamzapDecoderState decoder_state; | ||
141 | struct timer_list flush_timer; | ||
142 | int flush; | ||
143 | int in_use; | ||
144 | int timeout_enabled; | ||
145 | }; | ||
146 | |||
147 | |||
148 | /* local function prototypes */ | ||
149 | static int streamzap_probe(struct usb_interface *interface, | ||
150 | const struct usb_device_id *id); | ||
151 | static void streamzap_disconnect(struct usb_interface *interface); | ||
152 | static void usb_streamzap_irq(struct urb *urb); | ||
153 | static int streamzap_use_inc(void *data); | ||
154 | static void streamzap_use_dec(void *data); | ||
155 | static long streamzap_ioctl(struct file *filep, unsigned int cmd, | ||
156 | unsigned long arg); | ||
157 | static int streamzap_suspend(struct usb_interface *intf, pm_message_t message); | ||
158 | static int streamzap_resume(struct usb_interface *intf); | ||
159 | |||
160 | /* usb specific object needed to register this driver with the usb subsystem */ | ||
161 | |||
162 | static struct usb_driver streamzap_driver = { | ||
163 | .name = DRIVER_NAME, | ||
164 | .probe = streamzap_probe, | ||
165 | .disconnect = streamzap_disconnect, | ||
166 | .suspend = streamzap_suspend, | ||
167 | .resume = streamzap_resume, | ||
168 | .id_table = streamzap_table, | ||
169 | }; | ||
170 | |||
171 | static void stop_timer(struct usb_streamzap *sz) | ||
172 | { | ||
173 | unsigned long flags; | ||
174 | |||
175 | spin_lock_irqsave(&sz->timer_lock, flags); | ||
176 | if (sz->timer_running) { | ||
177 | sz->timer_running = 0; | ||
178 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
179 | del_timer_sync(&sz->delay_timer); | ||
180 | } else { | ||
181 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static void flush_timeout(unsigned long arg) | ||
186 | { | ||
187 | struct usb_streamzap *sz = (struct usb_streamzap *) arg; | ||
188 | |||
189 | /* finally start accepting data */ | ||
190 | sz->flush = 0; | ||
191 | } | ||
192 | static void delay_timeout(unsigned long arg) | ||
193 | { | ||
194 | unsigned long flags; | ||
195 | /* deliver data every 10 ms */ | ||
196 | static unsigned long timer_inc = | ||
197 | (10000/(1000000/HZ)) == 0 ? 1 : (10000/(1000000/HZ)); | ||
198 | struct usb_streamzap *sz = (struct usb_streamzap *) arg; | ||
199 | int data; | ||
200 | |||
201 | spin_lock_irqsave(&sz->timer_lock, flags); | ||
202 | |||
203 | if (!lirc_buffer_empty(sz->delay_buf) && | ||
204 | !lirc_buffer_full(sz->driver->rbuf)) { | ||
205 | lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); | ||
206 | lirc_buffer_write(sz->driver->rbuf, (unsigned char *) &data); | ||
207 | } | ||
208 | if (!lirc_buffer_empty(sz->delay_buf)) { | ||
209 | while (lirc_buffer_available(sz->delay_buf) < | ||
210 | STREAMZAP_BUF_LEN / 2 && | ||
211 | !lirc_buffer_full(sz->driver->rbuf)) { | ||
212 | lirc_buffer_read(sz->delay_buf, | ||
213 | (unsigned char *) &data); | ||
214 | lirc_buffer_write(sz->driver->rbuf, | ||
215 | (unsigned char *) &data); | ||
216 | } | ||
217 | if (sz->timer_running) { | ||
218 | sz->delay_timer.expires = jiffies + timer_inc; | ||
219 | add_timer(&sz->delay_timer); | ||
220 | } | ||
221 | } else { | ||
222 | sz->timer_running = 0; | ||
223 | } | ||
224 | |||
225 | if (!lirc_buffer_empty(sz->driver->rbuf)) | ||
226 | wake_up(&sz->driver->rbuf->wait_poll); | ||
227 | |||
228 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
229 | } | ||
230 | |||
231 | static void flush_delay_buffer(struct usb_streamzap *sz) | ||
232 | { | ||
233 | int data; | ||
234 | int empty = 1; | ||
235 | |||
236 | while (!lirc_buffer_empty(sz->delay_buf)) { | ||
237 | empty = 0; | ||
238 | lirc_buffer_read(sz->delay_buf, (unsigned char *) &data); | ||
239 | if (!lirc_buffer_full(sz->driver->rbuf)) { | ||
240 | lirc_buffer_write(sz->driver->rbuf, | ||
241 | (unsigned char *) &data); | ||
242 | } else { | ||
243 | dprintk("buffer overflow", sz->driver->minor); | ||
244 | } | ||
245 | } | ||
246 | if (!empty) | ||
247 | wake_up(&sz->driver->rbuf->wait_poll); | ||
248 | } | ||
249 | |||
250 | static void push(struct usb_streamzap *sz, unsigned char *data) | ||
251 | { | ||
252 | unsigned long flags; | ||
253 | |||
254 | spin_lock_irqsave(&sz->timer_lock, flags); | ||
255 | if (lirc_buffer_full(sz->delay_buf)) { | ||
256 | int read_data; | ||
257 | |||
258 | lirc_buffer_read(sz->delay_buf, | ||
259 | (unsigned char *) &read_data); | ||
260 | if (!lirc_buffer_full(sz->driver->rbuf)) { | ||
261 | lirc_buffer_write(sz->driver->rbuf, | ||
262 | (unsigned char *) &read_data); | ||
263 | } else { | ||
264 | dprintk("buffer overflow", sz->driver->minor); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | lirc_buffer_write(sz->delay_buf, data); | ||
269 | |||
270 | if (!sz->timer_running) { | ||
271 | sz->delay_timer.expires = jiffies + HZ/10; | ||
272 | add_timer(&sz->delay_timer); | ||
273 | sz->timer_running = 1; | ||
274 | } | ||
275 | |||
276 | spin_unlock_irqrestore(&sz->timer_lock, flags); | ||
277 | } | ||
278 | |||
279 | static void push_full_pulse(struct usb_streamzap *sz, | ||
280 | unsigned char value) | ||
281 | { | ||
282 | int pulse; | ||
283 | |||
284 | if (sz->idle) { | ||
285 | long deltv; | ||
286 | int tmp; | ||
287 | |||
288 | sz->signal_last = sz->signal_start; | ||
289 | do_gettimeofday(&sz->signal_start); | ||
290 | |||
291 | deltv = sz->signal_start.tv_sec-sz->signal_last.tv_sec; | ||
292 | if (deltv > 15) { | ||
293 | /* really long time */ | ||
294 | tmp = LIRC_SPACE(LIRC_VALUE_MASK); | ||
295 | } else { | ||
296 | tmp = (int) (deltv*1000000+ | ||
297 | sz->signal_start.tv_usec - | ||
298 | sz->signal_last.tv_usec); | ||
299 | tmp -= sz->sum; | ||
300 | tmp = LIRC_SPACE(tmp); | ||
301 | } | ||
302 | dprintk("ls %u", sz->driver->minor, tmp); | ||
303 | push(sz, (char *)&tmp); | ||
304 | |||
305 | sz->idle = 0; | ||
306 | sz->sum = 0; | ||
307 | } | ||
308 | |||
309 | pulse = ((int) value) * STREAMZAP_RESOLUTION; | ||
310 | pulse += STREAMZAP_RESOLUTION / 2; | ||
311 | sz->sum += pulse; | ||
312 | pulse = LIRC_PULSE(pulse); | ||
313 | |||
314 | dprintk("p %u", sz->driver->minor, pulse & PULSE_MASK); | ||
315 | push(sz, (char *)&pulse); | ||
316 | } | ||
317 | |||
318 | static void push_half_pulse(struct usb_streamzap *sz, | ||
319 | unsigned char value) | ||
320 | { | ||
321 | push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK)>>4); | ||
322 | } | ||
323 | |||
324 | static void push_full_space(struct usb_streamzap *sz, | ||
325 | unsigned char value) | ||
326 | { | ||
327 | int space; | ||
328 | |||
329 | space = ((int) value)*STREAMZAP_RESOLUTION; | ||
330 | space += STREAMZAP_RESOLUTION/2; | ||
331 | sz->sum += space; | ||
332 | space = LIRC_SPACE(space); | ||
333 | dprintk("s %u", sz->driver->minor, space); | ||
334 | push(sz, (char *)&space); | ||
335 | } | ||
336 | |||
337 | static void push_half_space(struct usb_streamzap *sz, | ||
338 | unsigned char value) | ||
339 | { | ||
340 | push_full_space(sz, value & STREAMZAP_SPACE_MASK); | ||
341 | } | ||
342 | |||
343 | /** | ||
344 | * usb_streamzap_irq - IRQ handler | ||
345 | * | ||
346 | * This procedure is invoked on reception of data from | ||
347 | * the usb remote. | ||
348 | */ | ||
349 | static void usb_streamzap_irq(struct urb *urb) | ||
350 | { | ||
351 | struct usb_streamzap *sz; | ||
352 | int len; | ||
353 | unsigned int i = 0; | ||
354 | |||
355 | if (!urb) | ||
356 | return; | ||
357 | |||
358 | sz = urb->context; | ||
359 | len = urb->actual_length; | ||
360 | |||
361 | switch (urb->status) { | ||
362 | case -ECONNRESET: | ||
363 | case -ENOENT: | ||
364 | case -ESHUTDOWN: | ||
365 | /* | ||
366 | * this urb is terminated, clean up. | ||
367 | * sz might already be invalid at this point | ||
368 | */ | ||
369 | dprintk("urb status: %d", -1, urb->status); | ||
370 | return; | ||
371 | default: | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | dprintk("received %d", sz->driver->minor, urb->actual_length); | ||
376 | if (!sz->flush) { | ||
377 | for (i = 0; i < urb->actual_length; i++) { | ||
378 | dprintk("%d: %x", sz->driver->minor, | ||
379 | i, (unsigned char) sz->buf_in[i]); | ||
380 | switch (sz->decoder_state) { | ||
381 | case PulseSpace: | ||
382 | if ((sz->buf_in[i]&STREAMZAP_PULSE_MASK) == | ||
383 | STREAMZAP_PULSE_MASK) { | ||
384 | sz->decoder_state = FullPulse; | ||
385 | continue; | ||
386 | } else if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) | ||
387 | == STREAMZAP_SPACE_MASK) { | ||
388 | push_half_pulse(sz, sz->buf_in[i]); | ||
389 | sz->decoder_state = FullSpace; | ||
390 | continue; | ||
391 | } else { | ||
392 | push_half_pulse(sz, sz->buf_in[i]); | ||
393 | push_half_space(sz, sz->buf_in[i]); | ||
394 | } | ||
395 | break; | ||
396 | case FullPulse: | ||
397 | push_full_pulse(sz, sz->buf_in[i]); | ||
398 | sz->decoder_state = IgnorePulse; | ||
399 | break; | ||
400 | case FullSpace: | ||
401 | if (sz->buf_in[i] == STREAMZAP_TIMEOUT) { | ||
402 | sz->idle = 1; | ||
403 | stop_timer(sz); | ||
404 | if (sz->timeout_enabled) { | ||
405 | int timeout = | ||
406 | LIRC_TIMEOUT | ||
407 | (STREAMZAP_TIMEOUT * | ||
408 | STREAMZAP_RESOLUTION); | ||
409 | push(sz, (char *)&timeout); | ||
410 | } | ||
411 | flush_delay_buffer(sz); | ||
412 | } else | ||
413 | push_full_space(sz, sz->buf_in[i]); | ||
414 | sz->decoder_state = PulseSpace; | ||
415 | break; | ||
416 | case IgnorePulse: | ||
417 | if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) == | ||
418 | STREAMZAP_SPACE_MASK) { | ||
419 | sz->decoder_state = FullSpace; | ||
420 | continue; | ||
421 | } | ||
422 | push_half_space(sz, sz->buf_in[i]); | ||
423 | sz->decoder_state = PulseSpace; | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | usb_submit_urb(urb, GFP_ATOMIC); | ||
430 | |||
431 | return; | ||
432 | } | ||
433 | |||
434 | static const struct file_operations streamzap_fops = { | ||
435 | .owner = THIS_MODULE, | ||
436 | .unlocked_ioctl = streamzap_ioctl, | ||
437 | .read = lirc_dev_fop_read, | ||
438 | .write = lirc_dev_fop_write, | ||
439 | .poll = lirc_dev_fop_poll, | ||
440 | .open = lirc_dev_fop_open, | ||
441 | .release = lirc_dev_fop_close, | ||
442 | }; | ||
443 | |||
444 | |||
445 | /** | ||
446 | * streamzap_probe | ||
447 | * | ||
448 | * Called by usb-core to associated with a candidate device | ||
449 | * On any failure the return value is the ERROR | ||
450 | * On success return 0 | ||
451 | */ | ||
452 | static int streamzap_probe(struct usb_interface *interface, | ||
453 | const struct usb_device_id *id) | ||
454 | { | ||
455 | struct usb_device *udev = interface_to_usbdev(interface); | ||
456 | struct usb_host_interface *iface_host; | ||
457 | struct usb_streamzap *sz; | ||
458 | struct lirc_driver *driver; | ||
459 | struct lirc_buffer *lirc_buf; | ||
460 | struct lirc_buffer *delay_buf; | ||
461 | char buf[63], name[128] = ""; | ||
462 | int retval = -ENOMEM; | ||
463 | int minor = 0; | ||
464 | |||
465 | /* Allocate space for device driver specific data */ | ||
466 | sz = kzalloc(sizeof(struct usb_streamzap), GFP_KERNEL); | ||
467 | if (sz == NULL) | ||
468 | return -ENOMEM; | ||
469 | |||
470 | sz->udev = udev; | ||
471 | sz->interface = interface; | ||
472 | |||
473 | /* Check to ensure endpoint information matches requirements */ | ||
474 | iface_host = interface->cur_altsetting; | ||
475 | |||
476 | if (iface_host->desc.bNumEndpoints != 1) { | ||
477 | err("%s: Unexpected desc.bNumEndpoints (%d)", __func__, | ||
478 | iface_host->desc.bNumEndpoints); | ||
479 | retval = -ENODEV; | ||
480 | goto free_sz; | ||
481 | } | ||
482 | |||
483 | sz->endpoint = &(iface_host->endpoint[0].desc); | ||
484 | if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) | ||
485 | != USB_DIR_IN) { | ||
486 | err("%s: endpoint doesn't match input device 02%02x", | ||
487 | __func__, sz->endpoint->bEndpointAddress); | ||
488 | retval = -ENODEV; | ||
489 | goto free_sz; | ||
490 | } | ||
491 | |||
492 | if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | ||
493 | != USB_ENDPOINT_XFER_INT) { | ||
494 | err("%s: endpoint attributes don't match xfer 02%02x", | ||
495 | __func__, sz->endpoint->bmAttributes); | ||
496 | retval = -ENODEV; | ||
497 | goto free_sz; | ||
498 | } | ||
499 | |||
500 | if (sz->endpoint->wMaxPacketSize == 0) { | ||
501 | err("%s: endpoint message size==0? ", __func__); | ||
502 | retval = -ENODEV; | ||
503 | goto free_sz; | ||
504 | } | ||
505 | |||
506 | /* Allocate the USB buffer and IRQ URB */ | ||
507 | |||
508 | sz->buf_in_len = sz->endpoint->wMaxPacketSize; | ||
509 | sz->buf_in = usb_alloc_coherent(sz->udev, sz->buf_in_len, | ||
510 | GFP_ATOMIC, &sz->dma_in); | ||
511 | if (sz->buf_in == NULL) | ||
512 | goto free_sz; | ||
513 | |||
514 | sz->urb_in = usb_alloc_urb(0, GFP_KERNEL); | ||
515 | if (sz->urb_in == NULL) | ||
516 | goto free_sz; | ||
517 | |||
518 | /* Connect this device to the LIRC sub-system */ | ||
519 | driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); | ||
520 | if (!driver) | ||
521 | goto free_sz; | ||
522 | |||
523 | lirc_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); | ||
524 | if (!lirc_buf) | ||
525 | goto free_driver; | ||
526 | if (lirc_buffer_init(lirc_buf, sizeof(int), STREAMZAP_BUF_LEN)) | ||
527 | goto kfree_lirc_buf; | ||
528 | |||
529 | delay_buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); | ||
530 | if (!delay_buf) | ||
531 | goto free_lirc_buf; | ||
532 | if (lirc_buffer_init(delay_buf, sizeof(int), STREAMZAP_BUF_LEN)) | ||
533 | goto kfree_delay_buf; | ||
534 | |||
535 | sz->driver = driver; | ||
536 | strcpy(sz->driver->name, DRIVER_NAME); | ||
537 | sz->driver->minor = -1; | ||
538 | sz->driver->sample_rate = 0; | ||
539 | sz->driver->code_length = sizeof(int) * 8; | ||
540 | sz->driver->features = LIRC_CAN_REC_MODE2 | | ||
541 | LIRC_CAN_GET_REC_RESOLUTION | | ||
542 | LIRC_CAN_SET_REC_TIMEOUT; | ||
543 | sz->driver->data = sz; | ||
544 | sz->driver->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; | ||
545 | sz->driver->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION; | ||
546 | sz->driver->rbuf = lirc_buf; | ||
547 | sz->delay_buf = delay_buf; | ||
548 | sz->driver->set_use_inc = &streamzap_use_inc; | ||
549 | sz->driver->set_use_dec = &streamzap_use_dec; | ||
550 | sz->driver->fops = &streamzap_fops; | ||
551 | sz->driver->dev = &interface->dev; | ||
552 | sz->driver->owner = THIS_MODULE; | ||
553 | |||
554 | sz->idle = 1; | ||
555 | sz->decoder_state = PulseSpace; | ||
556 | init_timer(&sz->delay_timer); | ||
557 | sz->delay_timer.function = delay_timeout; | ||
558 | sz->delay_timer.data = (unsigned long) sz; | ||
559 | sz->timer_running = 0; | ||
560 | spin_lock_init(&sz->timer_lock); | ||
561 | |||
562 | init_timer(&sz->flush_timer); | ||
563 | sz->flush_timer.function = flush_timeout; | ||
564 | sz->flush_timer.data = (unsigned long) sz; | ||
565 | /* Complete final initialisations */ | ||
566 | |||
567 | usb_fill_int_urb(sz->urb_in, udev, | ||
568 | usb_rcvintpipe(udev, sz->endpoint->bEndpointAddress), | ||
569 | sz->buf_in, sz->buf_in_len, usb_streamzap_irq, sz, | ||
570 | sz->endpoint->bInterval); | ||
571 | sz->urb_in->transfer_dma = sz->dma_in; | ||
572 | sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
573 | |||
574 | if (udev->descriptor.iManufacturer | ||
575 | && usb_string(udev, udev->descriptor.iManufacturer, | ||
576 | buf, sizeof(buf)) > 0) | ||
577 | strlcpy(name, buf, sizeof(name)); | ||
578 | |||
579 | if (udev->descriptor.iProduct | ||
580 | && usb_string(udev, udev->descriptor.iProduct, | ||
581 | buf, sizeof(buf)) > 0) | ||
582 | snprintf(name + strlen(name), sizeof(name) - strlen(name), | ||
583 | " %s", buf); | ||
584 | |||
585 | minor = lirc_register_driver(driver); | ||
586 | |||
587 | if (minor < 0) | ||
588 | goto free_delay_buf; | ||
589 | |||
590 | sz->driver->minor = minor; | ||
591 | |||
592 | usb_set_intfdata(interface, sz); | ||
593 | |||
594 | printk(KERN_INFO DRIVER_NAME "[%d]: %s on usb%d:%d attached\n", | ||
595 | sz->driver->minor, name, | ||
596 | udev->bus->busnum, sz->udev->devnum); | ||
597 | |||
598 | return 0; | ||
599 | |||
600 | free_delay_buf: | ||
601 | lirc_buffer_free(sz->delay_buf); | ||
602 | kfree_delay_buf: | ||
603 | kfree(delay_buf); | ||
604 | free_lirc_buf: | ||
605 | lirc_buffer_free(sz->driver->rbuf); | ||
606 | kfree_lirc_buf: | ||
607 | kfree(lirc_buf); | ||
608 | free_driver: | ||
609 | kfree(driver); | ||
610 | free_sz: | ||
611 | if (retval == -ENOMEM) | ||
612 | err("Out of memory"); | ||
613 | |||
614 | if (sz) { | ||
615 | usb_free_urb(sz->urb_in); | ||
616 | usb_free_coherent(udev, sz->buf_in_len, sz->buf_in, sz->dma_in); | ||
617 | kfree(sz); | ||
618 | } | ||
619 | |||
620 | return retval; | ||
621 | } | ||
622 | |||
623 | static int streamzap_use_inc(void *data) | ||
624 | { | ||
625 | struct usb_streamzap *sz = data; | ||
626 | |||
627 | if (!sz) { | ||
628 | dprintk("%s called with no context", -1, __func__); | ||
629 | return -EINVAL; | ||
630 | } | ||
631 | dprintk("set use inc", sz->driver->minor); | ||
632 | |||
633 | lirc_buffer_clear(sz->driver->rbuf); | ||
634 | lirc_buffer_clear(sz->delay_buf); | ||
635 | |||
636 | sz->flush_timer.expires = jiffies + HZ; | ||
637 | sz->flush = 1; | ||
638 | add_timer(&sz->flush_timer); | ||
639 | |||
640 | sz->urb_in->dev = sz->udev; | ||
641 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { | ||
642 | dprintk("open result = -EIO error submitting urb", | ||
643 | sz->driver->minor); | ||
644 | return -EIO; | ||
645 | } | ||
646 | sz->in_use++; | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static void streamzap_use_dec(void *data) | ||
652 | { | ||
653 | struct usb_streamzap *sz = data; | ||
654 | |||
655 | if (!sz) { | ||
656 | dprintk("%s called with no context", -1, __func__); | ||
657 | return; | ||
658 | } | ||
659 | dprintk("set use dec", sz->driver->minor); | ||
660 | |||
661 | if (sz->flush) { | ||
662 | sz->flush = 0; | ||
663 | del_timer_sync(&sz->flush_timer); | ||
664 | } | ||
665 | |||
666 | usb_kill_urb(sz->urb_in); | ||
667 | |||
668 | stop_timer(sz); | ||
669 | |||
670 | sz->in_use--; | ||
671 | } | ||
672 | |||
673 | static long streamzap_ioctl(struct file *filep, unsigned int cmd, | ||
674 | unsigned long arg) | ||
675 | { | ||
676 | int result = 0; | ||
677 | int val; | ||
678 | struct usb_streamzap *sz = lirc_get_pdata(filep); | ||
679 | |||
680 | switch (cmd) { | ||
681 | case LIRC_GET_REC_RESOLUTION: | ||
682 | result = put_user(STREAMZAP_RESOLUTION, (unsigned int *) arg); | ||
683 | break; | ||
684 | case LIRC_SET_REC_TIMEOUT: | ||
685 | result = get_user(val, (int *)arg); | ||
686 | if (result == 0) { | ||
687 | if (val == STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) | ||
688 | sz->timeout_enabled = 1; | ||
689 | else if (val == 0) | ||
690 | sz->timeout_enabled = 0; | ||
691 | else | ||
692 | result = -EINVAL; | ||
693 | } | ||
694 | break; | ||
695 | default: | ||
696 | return lirc_dev_fop_ioctl(filep, cmd, arg); | ||
697 | } | ||
698 | return result; | ||
699 | } | ||
700 | |||
701 | /** | ||
702 | * streamzap_disconnect | ||
703 | * | ||
704 | * Called by the usb core when the device is removed from the system. | ||
705 | * | ||
706 | * This routine guarantees that the driver will not submit any more urbs | ||
707 | * by clearing dev->udev. It is also supposed to terminate any currently | ||
708 | * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(), | ||
709 | * does not provide any way to do this. | ||
710 | */ | ||
711 | static void streamzap_disconnect(struct usb_interface *interface) | ||
712 | { | ||
713 | struct usb_streamzap *sz; | ||
714 | int errnum; | ||
715 | int minor; | ||
716 | |||
717 | sz = usb_get_intfdata(interface); | ||
718 | |||
719 | /* unregister from the LIRC sub-system */ | ||
720 | |||
721 | errnum = lirc_unregister_driver(sz->driver->minor); | ||
722 | if (errnum != 0) | ||
723 | dprintk("error in lirc_unregister: (returned %d)", | ||
724 | sz->driver->minor, errnum); | ||
725 | |||
726 | lirc_buffer_free(sz->delay_buf); | ||
727 | lirc_buffer_free(sz->driver->rbuf); | ||
728 | |||
729 | /* unregister from the USB sub-system */ | ||
730 | |||
731 | usb_free_urb(sz->urb_in); | ||
732 | |||
733 | usb_free_coherent(sz->udev, sz->buf_in_len, sz->buf_in, sz->dma_in); | ||
734 | |||
735 | minor = sz->driver->minor; | ||
736 | kfree(sz->driver->rbuf); | ||
737 | kfree(sz->driver); | ||
738 | kfree(sz->delay_buf); | ||
739 | kfree(sz); | ||
740 | |||
741 | printk(KERN_INFO DRIVER_NAME "[%d]: disconnected\n", minor); | ||
742 | } | ||
743 | |||
744 | static int streamzap_suspend(struct usb_interface *intf, pm_message_t message) | ||
745 | { | ||
746 | struct usb_streamzap *sz = usb_get_intfdata(intf); | ||
747 | |||
748 | printk(KERN_INFO DRIVER_NAME "[%d]: suspend\n", sz->driver->minor); | ||
749 | if (sz->in_use) { | ||
750 | if (sz->flush) { | ||
751 | sz->flush = 0; | ||
752 | del_timer_sync(&sz->flush_timer); | ||
753 | } | ||
754 | |||
755 | stop_timer(sz); | ||
756 | |||
757 | usb_kill_urb(sz->urb_in); | ||
758 | } | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int streamzap_resume(struct usb_interface *intf) | ||
763 | { | ||
764 | struct usb_streamzap *sz = usb_get_intfdata(intf); | ||
765 | |||
766 | lirc_buffer_clear(sz->driver->rbuf); | ||
767 | lirc_buffer_clear(sz->delay_buf); | ||
768 | |||
769 | if (sz->in_use) { | ||
770 | sz->flush_timer.expires = jiffies + HZ; | ||
771 | sz->flush = 1; | ||
772 | add_timer(&sz->flush_timer); | ||
773 | |||
774 | sz->urb_in->dev = sz->udev; | ||
775 | if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) { | ||
776 | dprintk("open result = -EIO error submitting urb", | ||
777 | sz->driver->minor); | ||
778 | return -EIO; | ||
779 | } | ||
780 | } | ||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | /** | ||
785 | * usb_streamzap_init | ||
786 | */ | ||
787 | static int __init usb_streamzap_init(void) | ||
788 | { | ||
789 | int result; | ||
790 | |||
791 | /* register this driver with the USB subsystem */ | ||
792 | result = usb_register(&streamzap_driver); | ||
793 | |||
794 | if (result) { | ||
795 | err("usb_register failed. Error number %d", | ||
796 | result); | ||
797 | return result; | ||
798 | } | ||
799 | |||
800 | printk(KERN_INFO DRIVER_NAME " " DRIVER_VERSION " registered\n"); | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /** | ||
805 | * usb_streamzap_exit | ||
806 | */ | ||
807 | static void __exit usb_streamzap_exit(void) | ||
808 | { | ||
809 | usb_deregister(&streamzap_driver); | ||
810 | } | ||
811 | |||
812 | |||
813 | module_init(usb_streamzap_init); | ||
814 | module_exit(usb_streamzap_exit); | ||
815 | |||
816 | MODULE_AUTHOR("Christoph Bartelmus, Greg Wickham, Adrian Dewhurst"); | ||
817 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
818 | MODULE_LICENSE("GPL"); | ||
819 | |||
820 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
821 | MODULE_PARM_DESC(debug, "Enable debugging messages"); | ||