• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file me1400_ext_irq.c
3  *
4  * @brief ME-1400 external interrupt subdevice instance.
5  * @note Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
6  * @author Guenter Gebhardt
7  * @author Krzysztof Gantzke	(k.gantzke@meilhaus.de)
8  */
9 
10 /*
11  * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
12  *
13  * This file is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  */
27 
28 #ifndef __KERNEL__
29 #  define __KERNEL__
30 #endif
31 
32 /*
33  * Includes
34  */
35 #include <linux/version.h>
36 #include <linux/module.h>
37 
38 #include <linux/slab.h>
39 #include <linux/spinlock.h>
40 #include <asm/io.h>
41 #include <linux/types.h>
42 #include <linux/interrupt.h>
43 
44 #include "medefines.h"
45 #include "meinternal.h"
46 #include "meerror.h"
47 #include "medebug.h"
48 #include "meids.h"
49 
50 #include "me1400_ext_irq.h"
51 #include "me1400_ext_irq_reg.h"
52 
53 /*
54  * Defines
55  */
56 #define ME1400_EXT_IRQ_MAGIC_NUMBER	0x1401	/**< The magic number of the class structure. */
57 #define ME1400_EXT_IRQ_NUMBER_CHANNELS 1	/**< One channel per counter. */
58 
59 /*
60  * Functions
61  */
62 
me1400_ext_irq_io_irq_start(struct me_subdevice * subdevice,struct file * filep,int channel,int irq_source,int irq_edge,int irq_arg,int flags)63 static int me1400_ext_irq_io_irq_start(struct me_subdevice *subdevice,
64 				       struct file *filep,
65 				       int channel,
66 				       int irq_source,
67 				       int irq_edge, int irq_arg, int flags)
68 {
69 	me1400_ext_irq_subdevice_t *instance;
70 	unsigned long cpu_flags;
71 	uint8_t tmp;
72 
73 	PDEBUG("executed.\n");
74 
75 	instance = (me1400_ext_irq_subdevice_t *) subdevice;
76 
77 	if (flags & ~ME_IO_IRQ_START_DIO_BIT) {
78 		PERROR("Invalid flag specified.\n");
79 		return ME_ERRNO_INVALID_FLAGS;
80 	}
81 
82 	if (channel) {
83 		PERROR("Invalid channel.\n");
84 		return ME_ERRNO_INVALID_CHANNEL;
85 	}
86 
87 	if (irq_source != ME_IRQ_SOURCE_DIO_LINE) {
88 		PERROR("Invalid irq source.\n");
89 		return ME_ERRNO_INVALID_IRQ_SOURCE;
90 	}
91 
92 	if (irq_edge != ME_IRQ_EDGE_RISING) {
93 		PERROR("Invalid irq edge.\n");
94 		return ME_ERRNO_INVALID_IRQ_EDGE;
95 	}
96 
97 	ME_SUBDEVICE_ENTER;
98 
99 	spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
100 
101 	spin_lock(instance->clk_src_reg_lock);
102 //                      // Enable IRQ on PLX
103 //                      tmp = inb(instance->plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN);
104 //                      outb(tmp, instance->plx_intcs_reg);
105 //                      PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp);
106 
107 	// Enable IRQ
108 	switch (instance->device_id) {
109 	case PCI_DEVICE_ID_MEILHAUS_ME140C:
110 	case PCI_DEVICE_ID_MEILHAUS_ME140D:
111 		tmp = inb(instance->ctrl_reg);
112 		tmp |= ME1400CD_EXT_IRQ_CLK_EN;
113 		outb(tmp, instance->ctrl_reg);
114 		PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
115 			   instance->reg_base,
116 			   instance->ctrl_reg - instance->reg_base, tmp);
117 		break;
118 
119 	default:
120 		outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg);
121 		PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
122 			   instance->reg_base,
123 			   instance->ctrl_reg - instance->reg_base,
124 			   ME1400AB_EXT_IRQ_IRQ_EN);
125 		break;
126 	}
127 	spin_unlock(instance->clk_src_reg_lock);
128 	instance->rised = 0;
129 	spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
130 
131 	ME_SUBDEVICE_EXIT;
132 
133 	return ME_ERRNO_SUCCESS;
134 }
135 
me1400_ext_irq_io_irq_wait(struct me_subdevice * subdevice,struct file * filep,int channel,int * irq_count,int * value,int time_out,int flags)136 static int me1400_ext_irq_io_irq_wait(struct me_subdevice *subdevice,
137 				      struct file *filep,
138 				      int channel,
139 				      int *irq_count,
140 				      int *value, int time_out, int flags)
141 {
142 	me1400_ext_irq_subdevice_t *instance;
143 	unsigned long cpu_flags;
144 	long t = 0;
145 	int err = ME_ERRNO_SUCCESS;
146 
147 	PDEBUG("executed.\n");
148 
149 	instance = (me1400_ext_irq_subdevice_t *) subdevice;
150 
151 	if (flags) {
152 		PERROR("Invalid flag specified.\n");
153 		return ME_ERRNO_INVALID_FLAGS;
154 	}
155 
156 	if (channel) {
157 		PERROR("Invalid channel.\n");
158 		return ME_ERRNO_INVALID_CHANNEL;
159 	}
160 
161 	if (time_out < 0) {
162 		PERROR("Invalid time out.\n");
163 		return ME_ERRNO_INVALID_TIMEOUT;
164 	}
165 
166 	if (time_out) {
167 		/* Convert to ticks */
168 		t = (time_out * HZ) / 1000;
169 
170 		if (t == 0)
171 			t = 1;
172 	}
173 
174 	ME_SUBDEVICE_ENTER;
175 
176 	if (instance->rised <= 0) {
177 		instance->rised = 0;
178 		if (time_out) {
179 			t = wait_event_interruptible_timeout(instance->
180 							     wait_queue,
181 							     (instance->rised !=
182 							      0), t);
183 
184 			if (t == 0) {
185 				PERROR("Wait on interrupt timed out.\n");
186 				err = ME_ERRNO_TIMEOUT;
187 			}
188 		} else {
189 			wait_event_interruptible(instance->wait_queue,
190 						 (instance->rised != 0));
191 		}
192 
193 		if (instance->rised < 0) {
194 			PERROR("Wait on interrupt aborted by user.\n");
195 			err = ME_ERRNO_CANCELLED;
196 		}
197 	}
198 
199 	if (signal_pending(current)) {
200 		PERROR("Wait on interrupt aborted by signal.\n");
201 		err = ME_ERRNO_SIGNAL;
202 	}
203 
204 	spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
205 	instance->rised = 0;
206 	*irq_count = instance->n;
207 	*value = 1;
208 	spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
209 
210 	ME_SUBDEVICE_EXIT;
211 
212 	return err;
213 }
214 
me1400_ext_irq_io_irq_stop(struct me_subdevice * subdevice,struct file * filep,int channel,int flags)215 static int me1400_ext_irq_io_irq_stop(struct me_subdevice *subdevice,
216 				      struct file *filep,
217 				      int channel, int flags)
218 {
219 	me1400_ext_irq_subdevice_t *instance;
220 	unsigned long cpu_flags;
221 	uint8_t tmp;
222 	int err = ME_ERRNO_SUCCESS;
223 
224 	PDEBUG("executed.\n");
225 
226 	instance = (me1400_ext_irq_subdevice_t *) subdevice;
227 
228 	if (flags) {
229 		PERROR("Invalid flag specified.\n");
230 		return ME_ERRNO_INVALID_FLAGS;
231 	}
232 
233 	if (channel) {
234 		PERROR("Invalid channel.\n");
235 		return ME_ERRNO_INVALID_CHANNEL;
236 	}
237 
238 	ME_SUBDEVICE_ENTER;
239 
240 	spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
241 	spin_lock(instance->clk_src_reg_lock);
242 //                      // Disable IRQ on PLX
243 //                      tmp = inb(instance->plx_intcs_reg) & ( ~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL | PLX_PCI_INT_EN));
244 //                      outb(tmp, instance->plx_intcs_reg);
245 //                      PDEBUG_REG("ctrl_reg outb(PLX:0x%lX)=0x%x\n", instance->plx_intcs_reg, tmp);
246 
247 	switch (instance->device_id) {
248 	case PCI_DEVICE_ID_MEILHAUS_ME140C:
249 	case PCI_DEVICE_ID_MEILHAUS_ME140D:
250 		tmp = inb(instance->ctrl_reg);
251 		tmp &= ~ME1400CD_EXT_IRQ_CLK_EN;
252 		outb(tmp, instance->ctrl_reg);
253 		PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
254 			   instance->reg_base,
255 			   instance->ctrl_reg - instance->reg_base, tmp);
256 
257 		break;
258 
259 	default:
260 		outb(0x00, instance->ctrl_reg);
261 		PDEBUG_REG("ctrl_reg outl(0x%lX+0x%lX)=0x%x\n",
262 			   instance->reg_base,
263 			   instance->ctrl_reg - instance->reg_base, 0x00);
264 		break;
265 	}
266 	spin_unlock(instance->clk_src_reg_lock);
267 	instance->rised = -1;
268 	spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
269 	wake_up_interruptible_all(&instance->wait_queue);
270 
271 	ME_SUBDEVICE_EXIT;
272 
273 	return err;
274 }
275 
me1400_ext_irq_io_reset_subdevice(struct me_subdevice * subdevice,struct file * filep,int flags)276 static int me1400_ext_irq_io_reset_subdevice(struct me_subdevice *subdevice,
277 					     struct file *filep, int flags)
278 {
279 	me1400_ext_irq_subdevice_t *instance =
280 	    (me1400_ext_irq_subdevice_t *) subdevice;
281 
282 	PDEBUG("executed.\n");
283 
284 	if (flags) {
285 		PERROR("Invalid flag specified.\n");
286 		return ME_ERRNO_INVALID_FLAGS;
287 	}
288 
289 	instance->n = 0;
290 	return me1400_ext_irq_io_irq_stop(subdevice, filep, 0, flags);
291 }
292 
me1400_ext_irq_query_number_channels(struct me_subdevice * subdevice,int * number)293 static int me1400_ext_irq_query_number_channels(struct me_subdevice *subdevice,
294 						int *number)
295 {
296 	PDEBUG("executed.\n");
297 	*number = ME1400_EXT_IRQ_NUMBER_CHANNELS;
298 	return ME_ERRNO_SUCCESS;
299 }
300 
me1400_ext_irq_query_subdevice_type(struct me_subdevice * subdevice,int * type,int * subtype)301 static int me1400_ext_irq_query_subdevice_type(struct me_subdevice *subdevice,
302 					       int *type, int *subtype)
303 {
304 	PDEBUG("executed.\n");
305 	*type = ME_TYPE_EXT_IRQ;
306 	*subtype = ME_SUBTYPE_SINGLE;
307 	return ME_ERRNO_SUCCESS;
308 }
309 
me1400_ext_irq_query_subdevice_caps(struct me_subdevice * subdevice,int * caps)310 static int me1400_ext_irq_query_subdevice_caps(struct me_subdevice *subdevice,
311 					       int *caps)
312 {
313 	PDEBUG("executed.\n");
314 	*caps = ME_CAPS_EXT_IRQ_EDGE_RISING;
315 	return ME_ERRNO_SUCCESS;
316 }
317 
me1400_ext_irq_query_subdevice_caps_args(struct me_subdevice * subdevice,int cap,int * args,int count)318 static int me1400_ext_irq_query_subdevice_caps_args(struct me_subdevice
319 						    *subdevice, int cap,
320 						    int *args, int count)
321 {
322 	PDEBUG("executed.\n");
323 	return ME_ERRNO_NOT_SUPPORTED;
324 }
325 
326 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
me1400_ext_irq_isr(int irq,void * dev_id)327 static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id)
328 #else
329 static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id,
330 				      struct pt_regs *regs)
331 #endif
332 {
333 	me1400_ext_irq_subdevice_t *instance;
334 	uint32_t status;
335 	uint8_t tmp;
336 
337 	instance = (me1400_ext_irq_subdevice_t *) dev_id;
338 
339 	if (irq != instance->irq) {
340 		PERROR("Incorrect interrupt num: %d.\n", irq);
341 		return IRQ_NONE;
342 	}
343 
344 	spin_lock(&instance->subdevice_lock);
345 	status = inl(instance->plx_intcs_reg);
346 //              if (!((status & PLX_LOCAL_INT1_STATE) && (status & PLX_LOCAL_INT1_EN) && (status & PLX_PCI_INT_EN)))
347 	if ((status &
348 	     (PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) !=
349 	    (PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) {
350 		spin_unlock(&instance->subdevice_lock);
351 		PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
352 		      jiffies, __func__, status);
353 		return IRQ_NONE;
354 	}
355 
356 	inl(instance->ctrl_reg);
357 
358 	PDEBUG("executed.\n");
359 
360 	instance->n++;
361 	instance->rised = 1;
362 
363 	switch (instance->device_id) {
364 
365 	case PCI_DEVICE_ID_MEILHAUS_ME140C:
366 	case PCI_DEVICE_ID_MEILHAUS_ME140D:
367 		spin_lock(instance->clk_src_reg_lock);
368 		tmp = inb(instance->ctrl_reg);
369 		tmp &= ~ME1400CD_EXT_IRQ_CLK_EN;
370 		outb(tmp, instance->ctrl_reg);
371 		PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
372 			   instance->reg_base,
373 			   instance->ctrl_reg - instance->reg_base, tmp);
374 		tmp |= ME1400CD_EXT_IRQ_CLK_EN;
375 		outb(tmp, instance->ctrl_reg);
376 		PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
377 			   instance->reg_base,
378 			   instance->ctrl_reg - instance->reg_base, tmp);
379 		spin_unlock(instance->clk_src_reg_lock);
380 
381 		break;
382 
383 	default:
384 		outb(0, instance->ctrl_reg);
385 		PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
386 			   instance->reg_base,
387 			   instance->ctrl_reg - instance->reg_base, 0);
388 		outb(ME1400AB_EXT_IRQ_IRQ_EN, instance->ctrl_reg);
389 		PDEBUG_REG("ctrl_reg outb(0x%lX+0x%lX)=0x%x\n",
390 			   instance->reg_base,
391 			   instance->ctrl_reg - instance->reg_base,
392 			   ME1400AB_EXT_IRQ_IRQ_EN);
393 		break;
394 	}
395 
396 	spin_unlock(&instance->subdevice_lock);
397 	wake_up_interruptible_all(&instance->wait_queue);
398 
399 	return IRQ_HANDLED;
400 }
401 
me1400_ext_irq_destructor(struct me_subdevice * subdevice)402 static void me1400_ext_irq_destructor(struct me_subdevice *subdevice)
403 {
404 	me1400_ext_irq_subdevice_t *instance;
405 	uint8_t tmp;
406 
407 	PDEBUG("executed.\n");
408 
409 	instance = (me1400_ext_irq_subdevice_t *) subdevice;
410 
411 	// Disable IRQ on PLX
412 	tmp =
413 	    inb(instance->
414 		plx_intcs_reg) & (~(PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL |
415 				    PLX_PCI_INT_EN));
416 	outb(tmp, instance->plx_intcs_reg);
417 	PDEBUG_REG("ctrl_reg outb(plx:0x%lX)=0x%x\n", instance->plx_intcs_reg,
418 		   tmp);
419 
420 	free_irq(instance->irq, (void *)instance);
421 	me_subdevice_deinit(&instance->base);
422 	kfree(instance);
423 }
424 
me1400_ext_irq_constructor(uint32_t device_id,uint32_t plx_reg_base,uint32_t me1400_reg_base,spinlock_t * clk_src_reg_lock,int irq)425 me1400_ext_irq_subdevice_t *me1400_ext_irq_constructor(uint32_t device_id,
426 						       uint32_t plx_reg_base,
427 						       uint32_t me1400_reg_base,
428 						       spinlock_t *
429 						       clk_src_reg_lock,
430 						       int irq)
431 {
432 	me1400_ext_irq_subdevice_t *subdevice;
433 	int err;
434 	uint8_t tmp;
435 
436 	PDEBUG("executed.\n");
437 
438 	/* Allocate memory for subdevice instance */
439 	subdevice = kmalloc(sizeof(me1400_ext_irq_subdevice_t), GFP_KERNEL);
440 
441 	if (!subdevice) {
442 		PERROR("Cannot get memory for 1400_ext_irq instance.\n");
443 		return NULL;
444 	}
445 
446 	memset(subdevice, 0, sizeof(me1400_ext_irq_subdevice_t));
447 
448 	/* Initialize subdevice base class */
449 	err = me_subdevice_init(&subdevice->base);
450 
451 	if (err) {
452 		PERROR("Cannot initialize subdevice base class instance.\n");
453 		kfree(subdevice);
454 		return NULL;
455 	}
456 	// Initialize spin locks.
457 	spin_lock_init(&subdevice->subdevice_lock);
458 	subdevice->clk_src_reg_lock = clk_src_reg_lock;
459 
460 	/* Initialize wait queue */
461 	init_waitqueue_head(&subdevice->wait_queue);
462 
463 	subdevice->irq = irq;
464 
465 	err = request_irq(irq, me1400_ext_irq_isr,
466 #ifdef IRQF_DISABLED
467 			  IRQF_DISABLED | IRQF_SHARED,
468 #else
469 			  SA_INTERRUPT | SA_SHIRQ,
470 #endif
471 			  ME1400_NAME, (void *)subdevice);
472 
473 	if (err) {
474 		PERROR("Can't get irq.\n");
475 		me_subdevice_deinit(&subdevice->base);
476 		kfree(subdevice);
477 		return NULL;
478 	}
479 	PINFO("Registered irq=%d.\n", subdevice->irq);
480 
481 	/* Initialize registers */
482 	subdevice->plx_intcs_reg = plx_reg_base + PLX_INTCSR_REG;
483 	subdevice->ctrl_reg = me1400_reg_base + ME1400AB_EXT_IRQ_CTRL_REG;
484 #ifdef MEDEBUG_DEBUG_REG
485 	subdevice->reg_base = me1400_reg_base;
486 #endif
487 
488 	// Enable IRQ on PLX
489 	tmp =
490 	    inb(subdevice->
491 		plx_intcs_reg) | (PLX_LOCAL_INT1_EN | PLX_LOCAL_INT1_POL |
492 				  PLX_PCI_INT_EN);
493 	outb(tmp, subdevice->plx_intcs_reg);
494 	PDEBUG_REG("ctrl_reg outb(Pplx:0x%lX)=0x%x\n", subdevice->plx_intcs_reg,
495 		   tmp);
496 
497 	/* Initialize the subdevice methods */
498 	subdevice->base.me_subdevice_io_irq_start = me1400_ext_irq_io_irq_start;
499 	subdevice->base.me_subdevice_io_irq_wait = me1400_ext_irq_io_irq_wait;
500 	subdevice->base.me_subdevice_io_irq_stop = me1400_ext_irq_io_irq_stop;
501 	subdevice->base.me_subdevice_io_reset_subdevice =
502 	    me1400_ext_irq_io_reset_subdevice;
503 	subdevice->base.me_subdevice_query_number_channels =
504 	    me1400_ext_irq_query_number_channels;
505 	subdevice->base.me_subdevice_query_subdevice_type =
506 	    me1400_ext_irq_query_subdevice_type;
507 	subdevice->base.me_subdevice_query_subdevice_caps =
508 	    me1400_ext_irq_query_subdevice_caps;
509 	subdevice->base.me_subdevice_query_subdevice_caps_args =
510 	    me1400_ext_irq_query_subdevice_caps_args;
511 	subdevice->base.me_subdevice_destructor = me1400_ext_irq_destructor;
512 
513 	subdevice->rised = 0;
514 	subdevice->n = 0;
515 
516 	return subdevice;
517 }
518