diff options
author | Manu Abraham <abraham.manu@gmail.com> | 2009-12-02 20:06:15 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-01-17 08:55:28 -0500 |
commit | bd1fcac0148fb4a44395227edb0ff8ee31e09de1 (patch) | |
tree | 81b593a8d39a1467a83e186cc0f850fd83e64283 /drivers | |
parent | 071e3060a5f482e5948608d55e28bc7f5dd759cd (diff) |
V4L/DVB (13705): [Mantis] FIX: Do not return IRQ_HANDLED in the unlikely case
Signed-off-by: Manu Abraham <manu@linuxtv.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/dvb/mantis/mantis_pci.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c new file mode 100644 index 000000000000..68ff1b2a0b3d --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_pci.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | Mantis PCI bridge driver | ||
3 | |||
4 | Copyright (C) 2005, 2006 Manu Abraham (abraham.manu@gmail.com) | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | #include <asm/pgtable.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <linux/kmod.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/device.h> | ||
28 | #include "mantis_common.h" | ||
29 | #include "mantis_core.h" | ||
30 | |||
31 | #include <asm/irq.h> | ||
32 | #include <linux/signal.h> | ||
33 | #include <linux/sched.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | |||
36 | unsigned int verbose = 1; | ||
37 | module_param(verbose, int, 0644); | ||
38 | MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); | ||
39 | |||
40 | unsigned int devs; | ||
41 | |||
42 | #define PCI_VENDOR_ID_MANTIS 0x1822 | ||
43 | #define PCI_DEVICE_ID_MANTIS_R11 0x4e35 | ||
44 | #define DRIVER_NAME "Mantis" | ||
45 | |||
46 | static struct pci_device_id mantis_pci_table[] = { | ||
47 | { PCI_DEVICE(PCI_VENDOR_ID_MANTIS, PCI_DEVICE_ID_MANTIS_R11) }, | ||
48 | { 0 }, | ||
49 | }; | ||
50 | |||
51 | MODULE_DEVICE_TABLE(pci, mantis_pci_table); | ||
52 | |||
53 | static irqreturn_t mantis_pci_irq(int irq, void *dev_id) | ||
54 | { | ||
55 | int i = 0, interrupts = 0; | ||
56 | u32 stat = 0, mask = 0, lstat = 0, mstat = 0; | ||
57 | struct mantis_pci *mantis; | ||
58 | |||
59 | mantis = (struct mantis_pci *) dev_id; | ||
60 | if (unlikely(mantis == NULL)) { | ||
61 | dprintk(verbose, MANTIS_ERROR, 1, "Mantis == NULL"); | ||
62 | return IRQ_NONE; | ||
63 | } | ||
64 | stat = mmread(MANTIS_INT_STAT); | ||
65 | mask = mmread(MANTIS_INT_MASK); | ||
66 | mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; | ||
67 | |||
68 | if (!(stat & mask)) { | ||
69 | dprintk(verbose, MANTIS_DEBUG, 1, "Not ours !"); | ||
70 | return IRQ_NONE; | ||
71 | } | ||
72 | mmwrite(lstat, MANTIS_INT_STAT); | ||
73 | interrupts = hweight32(stat); | ||
74 | dprintk(verbose, MANTIS_DEBUG, 0, "=== Interrupts[%04x/%04x]=%d [", stat, mask, interrupts); | ||
75 | |||
76 | while (lstat) { | ||
77 | if (lstat & MANTIS_INT_RISCEN) { | ||
78 | dprintk(verbose, MANTIS_DEBUG, 0, "* DMA enabl *"); | ||
79 | lstat &= ~MANTIS_INT_RISCEN; | ||
80 | |||
81 | } else if (lstat & MANTIS_INT_I2CRACK) { | ||
82 | dprintk(verbose, MANTIS_DEBUG, 0, "* I2C R-ACK *"); | ||
83 | mantis->mantis_int_stat = stat; | ||
84 | mantis->mantis_int_mask = mask; | ||
85 | wake_up(&mantis->i2c_wq); | ||
86 | lstat &= ~MANTIS_INT_I2CRACK; | ||
87 | |||
88 | } else if (lstat & MANTIS_INT_PCMCIA7) { | ||
89 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-07 *"); | ||
90 | lstat &= ~MANTIS_INT_PCMCIA7; | ||
91 | |||
92 | } else if (lstat & MANTIS_INT_PCMCIA6) { | ||
93 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-06 *"); | ||
94 | lstat &= ~MANTIS_INT_PCMCIA6; | ||
95 | |||
96 | } else if (lstat & MANTIS_INT_PCMCIA5) { | ||
97 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-05 *"); | ||
98 | lstat &= ~MANTIS_INT_PCMCIA5; | ||
99 | |||
100 | } else if (lstat & MANTIS_INT_PCMCIA4) { | ||
101 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-04 *"); | ||
102 | lstat &= ~MANTIS_INT_PCMCIA4; | ||
103 | |||
104 | } else if (lstat & MANTIS_INT_PCMCIA3) { | ||
105 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-03 *"); | ||
106 | lstat &= ~MANTIS_INT_PCMCIA3; | ||
107 | |||
108 | } else if (lstat & MANTIS_INT_PCMCIA2) { | ||
109 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-02 *"); | ||
110 | lstat &= ~MANTIS_INT_PCMCIA2; | ||
111 | |||
112 | } else if (lstat & MANTIS_INT_PCMCIA1) { | ||
113 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-01 *"); | ||
114 | lstat &= ~MANTIS_INT_PCMCIA1; | ||
115 | |||
116 | } else if (lstat & MANTIS_INT_PCMCIA0) { | ||
117 | dprintk(verbose, MANTIS_DEBUG, 0, "* PCMCIA-00 *"); | ||
118 | lstat &= ~MANTIS_INT_PCMCIA0; | ||
119 | |||
120 | } else if (lstat & MANTIS_INT_IRQ0) { | ||
121 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT IRQ-0 *"); | ||
122 | lstat &= ~MANTIS_INT_IRQ0; | ||
123 | |||
124 | } else if (lstat & MANTIS_INT_IRQ1) { | ||
125 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT IRQ-1 *"); | ||
126 | lstat &= ~MANTIS_INT_IRQ1; | ||
127 | |||
128 | } else if (lstat & MANTIS_INT_OCERR) { | ||
129 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT OCERR *"); | ||
130 | lstat &= ~MANTIS_INT_OCERR; | ||
131 | |||
132 | } else if (lstat & MANTIS_INT_PABORT) { | ||
133 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT PABRT *"); | ||
134 | lstat &= ~MANTIS_INT_PABORT; | ||
135 | |||
136 | } else if (lstat & MANTIS_INT_RIPERR) { | ||
137 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT RIPRR *"); | ||
138 | lstat &= ~MANTIS_INT_RIPERR; | ||
139 | |||
140 | } else if (lstat & MANTIS_INT_PPERR) { | ||
141 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT PPERR *"); | ||
142 | lstat &= ~MANTIS_INT_PPERR; | ||
143 | |||
144 | } else if (lstat & MANTIS_INT_FTRGT) { | ||
145 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT FTRGT *"); | ||
146 | lstat &= ~MANTIS_INT_FTRGT; | ||
147 | |||
148 | } else if (lstat & MANTIS_INT_RISCI) { | ||
149 | dprintk(verbose, MANTIS_DEBUG, 0, "* INT RISCI *"); | ||
150 | mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; | ||
151 | tasklet_schedule(&mantis->tasklet); | ||
152 | lstat &= ~MANTIS_INT_RISCI; | ||
153 | |||
154 | } else if (lstat & MANTIS_INT_I2CDONE) { | ||
155 | dprintk(verbose, MANTIS_DEBUG, 0, "* I2C DONE *"); | ||
156 | mantis->mantis_int_stat = stat; | ||
157 | mantis->mantis_int_mask = mask; | ||
158 | lstat &= ~MANTIS_INT_I2CDONE; | ||
159 | } else { | ||
160 | dprintk(verbose, MANTIS_DEBUG, 0, | ||
161 | "* Unknown [%04x/%04x] *", stat, mask); | ||
162 | break; | ||
163 | } | ||
164 | i++; | ||
165 | if (i > interrupts) { | ||
166 | dprintk(verbose, MANTIS_ERROR, 1, "going Loopy ! -- BREAK --"); | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | dprintk(verbose, MANTIS_DEBUG, 0, "] ===\n"); | ||
171 | |||
172 | return IRQ_HANDLED; | ||
173 | } | ||
174 | |||
175 | |||
176 | static int __devinit mantis_pci_probe(struct pci_dev *pdev, | ||
177 | const struct pci_device_id *mantis_pci_table) | ||
178 | { | ||
179 | u8 revision, latency; | ||
180 | struct mantis_pci *mantis; | ||
181 | int ret = 0; | ||
182 | |||
183 | devs++; | ||
184 | |||
185 | mantis = kmalloc(sizeof (struct mantis_pci), GFP_KERNEL); | ||
186 | if (mantis == NULL) { | ||
187 | printk("%s: Out of memory\n", __func__); | ||
188 | ret = -ENOMEM; | ||
189 | goto err; | ||
190 | } | ||
191 | memset(mantis, 0, sizeof (struct mantis_pci)); | ||
192 | mantis->num = devs; | ||
193 | if (pci_enable_device(pdev)) { | ||
194 | dprintk(verbose, MANTIS_ERROR, 1, "Mantis PCI enable failed"); | ||
195 | ret = -ENODEV; | ||
196 | goto err; | ||
197 | } | ||
198 | mantis->mantis_addr = pci_resource_start(pdev, 0); | ||
199 | if (!request_mem_region(pci_resource_start(pdev, 0), | ||
200 | pci_resource_len(pdev, 0), DRIVER_NAME)) { | ||
201 | ret = -ENODEV; | ||
202 | goto err0; | ||
203 | } | ||
204 | |||
205 | if ((mantis->mantis_mmio = ioremap(mantis->mantis_addr, 0x1000)) == NULL) { | ||
206 | dprintk(verbose, MANTIS_ERROR, 1, "IO remap failed"); | ||
207 | ret = -ENODEV; | ||
208 | goto err1; | ||
209 | } | ||
210 | |||
211 | // Clear and disable all interrupts at startup | ||
212 | // to avoid lockup situations | ||
213 | mmwrite(0x00, MANTIS_INT_MASK); | ||
214 | if (request_irq(pdev->irq, mantis_pci_irq, IRQF_SHARED | IRQF_DISABLED, | ||
215 | DRIVER_NAME, mantis) < 0) { | ||
216 | |||
217 | dprintk(verbose, MANTIS_ERROR, 1, "Mantis IRQ reg failed"); | ||
218 | ret = -ENODEV; | ||
219 | goto err2; | ||
220 | } | ||
221 | pci_set_master(pdev); | ||
222 | pci_set_drvdata(pdev, mantis); | ||
223 | pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); | ||
224 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); | ||
225 | mantis->latency = latency; | ||
226 | mantis->revision = revision; | ||
227 | mantis->pdev = pdev; | ||
228 | init_waitqueue_head(&mantis->i2c_wq); | ||
229 | |||
230 | // CAM bypass | ||
231 | //mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ1, MANTIS_INT_MASK); | ||
232 | dprintk(verbose, MANTIS_INFO, 1, "gpif status: %04x irqcfg: %04x", mmread(0x9c), mmread(0x98)); | ||
233 | if ((mmread(0x9c) & 0x200) != 0) { //CAM inserted | ||
234 | msleep_interruptible(1); | ||
235 | if ((mmread(0x9c) & 0x200) != 0) | ||
236 | mmwrite(((mmread(0x98) | 0x01) & ~0x02), 0x98); | ||
237 | else | ||
238 | mmwrite(((mmread(0x98) | 0x02) & ~0x01), 0x98); | ||
239 | |||
240 | } else { | ||
241 | mmwrite(((mmread(0x98) | 0x02) & ~0x01), 0x98); | ||
242 | } | ||
243 | mantis_set_direction(mantis, 0); | ||
244 | |||
245 | // default latency if none specified | ||
246 | if (!latency) | ||
247 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 32); | ||
248 | dprintk(verbose, MANTIS_ERROR, 0, "Mantis Rev %d, ", | ||
249 | mantis->revision); | ||
250 | |||
251 | dprintk(verbose, MANTIS_ERROR, 0, | ||
252 | "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", | ||
253 | pdev->irq, mantis->latency, | ||
254 | mantis->mantis_addr, mantis->mantis_mmio); | ||
255 | |||
256 | // No more PCI specific stuff ! | ||
257 | if (mantis_core_init(mantis) < 0) { | ||
258 | dprintk(verbose, MANTIS_ERROR, 1, "Mantis core init failed"); | ||
259 | ret = -ENODEV; | ||
260 | goto err2; | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | |||
265 | // Error conditions .. | ||
266 | err2: | ||
267 | dprintk(verbose, MANTIS_DEBUG, 1, "Err: IO Unmap"); | ||
268 | if (mantis->mantis_mmio) | ||
269 | iounmap(mantis->mantis_mmio); | ||
270 | err1: | ||
271 | dprintk(verbose, MANTIS_DEBUG, 1, "Err: Release regions"); | ||
272 | release_mem_region(pci_resource_start(pdev, 0), | ||
273 | pci_resource_len(pdev, 0)); | ||
274 | pci_disable_device(pdev); | ||
275 | err0: | ||
276 | dprintk(verbose, MANTIS_DEBUG, 1, "Err: Free"); | ||
277 | kfree(mantis); | ||
278 | err: | ||
279 | dprintk(verbose, MANTIS_DEBUG, 1, "Err:"); | ||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | static void __devexit mantis_pci_remove(struct pci_dev *pdev) | ||
284 | { | ||
285 | struct mantis_pci *mantis = pci_get_drvdata(pdev); | ||
286 | |||
287 | if (mantis == NULL) { | ||
288 | dprintk(verbose, MANTIS_ERROR, 1, "Aeio, Mantis NULL ptr"); | ||
289 | return; | ||
290 | } | ||
291 | mantis_core_exit(mantis); | ||
292 | dprintk(verbose, MANTIS_ERROR, 1, "Removing -->Mantis irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p", | ||
293 | pdev->irq, mantis->latency, mantis->mantis_addr, | ||
294 | mantis->mantis_mmio); | ||
295 | |||
296 | free_irq(pdev->irq, mantis); | ||
297 | pci_release_regions(pdev); | ||
298 | if (mantis_dma_exit(mantis) < 0) | ||
299 | dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); | ||
300 | |||
301 | pci_set_drvdata(pdev, NULL); | ||
302 | pci_disable_device(pdev); | ||
303 | kfree(mantis); | ||
304 | } | ||
305 | |||
306 | static struct pci_driver mantis_pci_driver = { | ||
307 | .name = DRIVER_NAME, | ||
308 | .id_table = mantis_pci_table, | ||
309 | .probe = mantis_pci_probe, | ||
310 | .remove = mantis_pci_remove, | ||
311 | }; | ||
312 | |||
313 | static int __devinit mantis_pci_init(void) | ||
314 | { | ||
315 | return pci_register_driver(&mantis_pci_driver); | ||
316 | } | ||
317 | |||
318 | static void __devexit mantis_pci_exit(void) | ||
319 | { | ||
320 | pci_unregister_driver(&mantis_pci_driver); | ||
321 | } | ||
322 | |||
323 | module_init(mantis_pci_init); | ||
324 | module_exit(mantis_pci_exit); | ||
325 | |||
326 | MODULE_DESCRIPTION("Mantis PCI DTV bridge driver"); | ||
327 | MODULE_AUTHOR("Manu Abraham"); | ||
328 | MODULE_LICENSE("GPL"); | ||