1 /* -*- linux-c -*- */
2 /*
3 * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 **/
11
12 /* Standard in kernel modules */
13 #include <linux/module.h> /* Specifically, a module */
14
15 #include <asm/io.h>
16 #include <linux/timer.h>
17 #include <linux/interrupt.h>
18 #include <linux/tty.h>
19 #include <linux/tty_flip.h>
20 #include <linux/mm.h>
21 #include <linux/version.h>
22 #include <asm/uaccess.h>
23 #include <linux/pci.h>
24 #include "8253xctl.h"
25 #include "8253xmcs.h"
26
27 /*
28 * ----------------------------------------------------------------------
29 *
30 * Here starts the interrupt handling routines. All of the following
31 * subroutines are declared as inline and are folded into
32 * sab8253x_interrupt(). They were separated out for readability's sake.
33 *
34 * Note: sab8253x_interrupt() is a "fast" interrupt, which means that it
35 * runs with interrupts turned off. People who may want to modify
36 * sab8253x_interrupt() should try to keep the interrupt handler as fast as
37 * possible. After you are done making modifications, it is not a bad
38 * idea to do:
39 *
40 * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
41 *
42 * and look at the resulting assemble code in serial.s.
43 *
44 * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
45 * -----------------------------------------------------------------------
46 */
47
48 /* Note: the inline interrupt routines constitute the smallest hardware
49 unit that must be examined when an interrupt comes up. On the 4520
50 type cards, two ESCC2s must be examined. Because the ESCC2s are in
51 a null terminated list the sab82532_interrupt also works for 2 port/1 port
52 single ESCC2 cards.
53
54 On an 8520 type card there is but one ESCC8 thus the sab82538_interrupt
55 routine does not walk through a list. But this requires some contortion
56 in dealing with the multichannel server. The multichannel server has
57 at most 4 channel interface modules (CIM) 1/EB. Each CIM has at most
58 two ESCC8s, thus the host card can have a list of 8 ESCC8s. But by
59 walking the CIMs the exact ESCC8 that is interrupting can be identified.
60 Thus despite the complexity, really the MCS is a collection of 8520 type
61 cards multiplexed on one interrupt. Thus after making some temporary
62 modifications of the board structure, the generic interrupt handler invokes
63 sab82538_interrupt handler just as for an 8520 type card.
64 */
65
66 /* static forces inline compilation */
sab82532_interrupt(int irq,void * dev_id,struct pt_regs * regs)67 static void inline sab82532_interrupt(int irq, void *dev_id, struct pt_regs *regs)
68 {
69 struct sab_port *port;
70 struct sab_chip *chip=NULL;
71 struct sab_board *bptr = (struct sab_board*) dev_id;
72 union sab8253x_irq_status status;
73 unsigned char gis;
74
75 for(chip = bptr->board_chipbase; chip != NULL; chip = chip->next_by_board)
76 {
77 port= chip->c_portbase;
78 gis = READB(port, gis); /* Global! */
79 status.stat=0;
80
81 /* Since the PORT interrupt are global,
82 * we do check all the ports for this chip
83 */
84
85 /* A 2 ports chip */
86
87 if(!(gis & SAB82532_GIS_MASK))
88 {
89 continue; /* no interrupt on this chip */
90 }
91
92 if (gis & SAB82532_GIS_ISA0)
93 {
94 status.sreg.isr0 = READB(port, isr0);
95 }
96 else
97 {
98 status.sreg.isr0 = 0;
99 }
100 if (gis & SAB82532_GIS_ISA1)
101 {
102 status.sreg.isr1 = READB(port, isr1);
103 }
104 else
105 {
106 status.sreg.isr1 = 0;
107 }
108
109 if (gis & SAB82532_GIS_PI)
110 {
111 status.sreg.pis = READB(port, pis);
112 }
113 else
114 {
115 status.sreg.pis = 0;
116 }
117
118 if (status.stat)
119 {
120 if (status.images[ISR0_IDX] & port->receive_test)
121 {
122 (*port->receive_chars)(port, &status); /* when the fifo is full */
123 /* no time to schedule thread*/
124 }
125
126 if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
127 (status.images[port->cts.irq] & port->cts.irqmask) ||
128 (status.images[port->dsr.irq] & port->dsr.irqmask) ||
129 (status.images[ISR1_IDX] & port->check_status_test))
130 {
131 (*port->check_status)(port, &status); /* this stuff should be */
132 /* be moveable to scheduler */
133 /* thread*/
134 }
135
136 if (status.images[ISR1_IDX] & port->transmit_test)
137 {
138 (*port->transmit_chars)(port, &status); /* needs to be moved to task */
139 }
140 }
141
142 /* Get to next port on chip */
143 port = port->next_by_chip;
144 /* Port B */
145 if (gis & SAB82532_GIS_ISB0)
146 {
147 status.images[ISR0_IDX] = READB(port, isr0);
148 }
149 else
150 {
151 status.images[ISR0_IDX] = 0;
152 }
153 if (gis & SAB82532_GIS_ISB1)
154 {
155 status.images[ISR1_IDX] = READB(port,isr1);
156 }
157 else
158 {
159 status.images[ISR1_IDX] = 0;
160 }
161 /* DO NOT SET PIS. IT was reset! */
162
163
164 if (status.stat)
165 {
166 if (status.images[ISR0_IDX] & port->receive_test)
167 {
168 (*port->receive_chars)(port, &status);
169 }
170 if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
171 (status.images[port->cts.irq] & port->cts.irqmask) ||
172 (status.images[port->dsr.irq] & port->dsr.irqmask) ||
173 (status.images[ISR1_IDX] & port->check_status_test))
174 {
175 (*port->check_status)(port, &status);
176 }
177 if (status.images[ISR1_IDX] & port->transmit_test)
178 {
179 (*port->transmit_chars)(port, &status);
180 }
181 }
182 }
183 }
184
sab82538_interrupt(int irq,void * dev_id,struct pt_regs * regs)185 static void inline sab82538_interrupt(int irq, void *dev_id, struct pt_regs *regs)
186 {
187 struct sab_port *port;
188 struct sab_chip *chip=NULL;
189 struct sab_board *bptr = (struct sab_board*) dev_id;
190 union sab8253x_irq_status status;
191 unsigned char gis,i;
192
193 chip = bptr->board_chipbase;
194 port = chip->c_portbase;
195
196 gis = READB(port, gis); /* Global! */
197 status.stat=0;
198
199 /* Since the PORT interrupt are global,
200 * we do check all the ports for this chip
201 */
202
203 /* 8 ports chip */
204 if(!(gis & SAB82538_GIS_MASK))
205 {
206 return;
207 }
208
209 if(gis & SAB82538_GIS_CII)
210 { /* A port interrupt! */
211 /* Get the port */
212 int portindex;
213
214 portindex = (gis & SAB82538_GIS_CHNL_MASK);
215
216 port = chip->c_portbase;
217
218 while(portindex)
219 {
220 port = port->next_by_chip;
221 --portindex;
222 }
223
224 status.images[ISR0_IDX] = READB(port,isr0);
225 status.images[ISR1_IDX] = READB(port,isr1);
226 if (gis & SAB82538_GIS_PIC)
227 {
228 status.images[PIS_IDX] =
229 (*port->readbyte)(port,
230 ((unsigned char *)(port->regs)) +
231 SAB82538_REG_PIS_C);
232 }
233 else
234 {
235 status.images[PIS_IDX] = 0;
236 }
237
238 if (status.stat)
239 {
240 if (status.images[ISR0_IDX] & port->receive_test)
241 {
242 (*port->receive_chars)(port, &status);
243 }
244 if ((status.images[port->dcd.irq] & port->dcd.irqmask) ||
245 (status.images[port->cts.irq] & port->cts.irqmask) ||
246 (status.images[port->dsr.irq] & port->dsr.irqmask) ||
247 (status.images[ISR1_IDX] & port->check_status_test))
248 {
249 (*port->check_status)(port, &status);
250 }
251 /*
252 * We know that with 8 ports chip, the bit corresponding to channel
253 * number is used in the parallel port... So we clear it
254 * Not too elegant!
255 */
256 status.images[PIS_IDX] &= ~(1 << (gis&SAB82538_GIS_CHNL_MASK));
257 if (status.images[ISR1_IDX] & port->transmit_test)
258 {
259 (*port->transmit_chars)(port, &status);
260 }
261 }
262 }
263
264 /*
265 * Now we handle the "channel interrupt" case. The chip manual for the
266 * 8 ports chip states that "channel" and "port" interrupt are set
267 * independently so we still must check the parrallel port
268 *
269 * We should probably redesign the whole thing to be less AD HOC that we
270 * are now... We know that port C is used for DSR so we only check that one.
271 * PIS for port C was already recorded in status.images[PIS_IDX], so we
272 * check the ports that are set
273 */
274
275 if (status.images[PIS_IDX])
276 {
277 for(i=0, port = chip->c_portbase;
278 i < chip->c_nports;
279 i++, port=port->next_by_chip)
280 {
281 if(status.images[PIS_IDX] & (0x1 << i))
282 { /* Match */
283 /* Checking DSR */
284 if(port->dsr.inverted)
285 {
286 port->dsr.val = (((*port->readbyte)
287 (port, port->dsr.reg) &
288 port->dsr.mask) ? 0 : 1);
289 }
290 else
291 {
292 port->dsr.val = ((*port->readbyte)(port, port->dsr.reg) &
293 port->dsr.mask);
294 }
295
296 port->icount.dsr++;
297 wake_up_interruptible(&port->delta_msr_wait); /* in case waiting on modem change */
298 }
299 }
300 }
301 }
302
303 /*
304 * This is the serial driver's generic interrupt routine
305 */
306
sab8253x_interrupt(int irq,void * dev_id,struct pt_regs * regs)307 void sab8253x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
308 {
309 extern SAB_BOARD *AuraBoardESCC2IrqRoot[];
310 extern SAB_BOARD *AuraBoardESCC8IrqRoot[];
311 extern SAB_BOARD *AuraBoardMCSIrqRoot[];
312 AURA_CIM *cim;
313 SAB_CHIP *chip;
314 SAB_PORT *port;
315 register SAB_BOARD *boardptr;
316 register unsigned char intrmask;
317 unsigned char stat;
318 SAB_CHIP *save_chiplist;
319 SAB_PORT *save_portlist;
320
321 if((irq < 0) || (irq >= NUMINTS))
322 {
323 printk(KERN_ALERT "sab8253x: bad interrupt value %i.\n", irq);
324 return;
325 }
326 /* walk through all the cards on the interrupt that occurred. */
327 for(boardptr = AuraBoardESCC2IrqRoot[irq]; boardptr != NULL; boardptr = boardptr->next_on_interrupt)
328 {
329 sab82532_interrupt(irq, boardptr, regs);
330 }
331
332 for(boardptr = AuraBoardESCC8IrqRoot[irq]; boardptr != NULL; boardptr = boardptr->next_on_interrupt)
333 {
334 sab82538_interrupt(irq, boardptr, regs);
335 }
336
337 for(boardptr = AuraBoardMCSIrqRoot[irq]; boardptr != NULL; boardptr = boardptr->next_on_interrupt)
338 {
339
340 while(1)
341 {
342 writeb(0, (unsigned char*)(boardptr->CIMCMD_REG + CIMCMD_WRINTDIS)); /* prevent EBs from raising
343 * any more ints through the
344 * host card */
345 stat = ~(unsigned char) /* active low !!!!! */
346 readw((unsigned short*)
347 (((unsigned char*)boardptr->CIMCMD_REG) + CIMCMD_RDINT)); /* read out the ints */
348 /* write to the MIC csr to reset the PCI interrupt */
349 writeb(0, (unsigned char*)(boardptr->MICCMD_REG + MICCMD_MICCSR));
350 /* reset the interrupt generation
351 * hardware on the host card*/
352 /* now, write to the CIM interrupt ena to re-enable interrupt generation */
353 writeb(0, (unsigned char*)(boardptr->CIMCMD_REG + CIMCMD_WRINTENA)); /* allow EBs to request ints
354 * through the host card */
355 if(!stat)
356 {
357 break;
358 }
359 cim = boardptr->b_cimbase; /* cims in reverse order */
360 for(intrmask = boardptr->b_intrmask;
361 intrmask != 0;
362 intrmask <<= 2, stat <<=2)
363 {
364 if(cim == NULL)
365 {
366 break; /* no cim no ports */
367 }
368 if((intrmask & 0xc0) == 0) /* means no cim for these ints */
369 { /* cim not on list do not go to next */
370 continue;
371 }
372 save_portlist = boardptr->board_portbase;
373 save_chiplist = boardptr->board_chipbase;
374 /* the goal is temporarily to make the structures
375 * look like 8x20 structures -- thus if I find
376 * a bug related to escc8s I need fix it in
377 * only one place. */
378 switch(stat & 0xc0) /* possible ints */
379 {
380 default:
381 break;
382
383 case 0x80: /* esccB */
384 chip = cim->ci_chipbase;
385 if(!chip)
386 {
387 printk(KERN_ALERT "aura mcs: missing cim.\n");
388 break;
389 }
390 chip = chip->next_by_cim;
391 if(!chip)
392 {
393 printk(KERN_ALERT "aura mcs: missing 2nd cim.\n");
394 break;
395 }
396 port = chip->c_portbase;
397 boardptr->board_portbase = port;
398 boardptr->board_chipbase = chip;
399 sab82538_interrupt(irq, boardptr, regs);
400 break;
401
402 case 0x40: /* esccA */
403 chip = cim->ci_chipbase;
404 if(!chip)
405 {
406 printk(KERN_ALERT "aura mcs: missing cim.\n");
407 break;
408 }
409 port = chip->c_portbase;
410 boardptr->board_portbase = port;
411 boardptr->board_chipbase = chip;
412 sab82538_interrupt(irq, boardptr, regs);
413 break;
414
415 case 0xc0: /* esccB and esccA */
416 chip = cim->ci_chipbase;
417 if(!chip)
418 {
419 printk(KERN_ALERT "aura mcs: missing cim.\n");
420 break;
421 }
422 port = chip->c_portbase;
423 boardptr->board_portbase = port;
424 boardptr->board_chipbase = chip;
425 sab82538_interrupt(irq, boardptr, regs);
426
427 chip = cim->ci_chipbase;
428 if(!chip)
429 {
430 printk(KERN_ALERT "aura mcs: missing cim.\n");
431 break;
432 }
433 chip = chip->next_by_cim;
434 if(!chip)
435 {
436 printk(KERN_ALERT "aura mcs: missing 2nd cim.\n");
437 break;
438 }
439 port = chip->c_portbase;
440 boardptr->board_portbase = port;
441 boardptr->board_chipbase = chip;
442 sab82538_interrupt(irq, boardptr, regs);
443 break;
444 }
445 boardptr->board_portbase = save_portlist;
446 boardptr->board_chipbase = save_chiplist;
447 cim = cim->next_by_mcs;
448 }
449 }
450 }
451 }
452
453 /*
454 * -------------------------------------------------------------------
455 * Here ends the serial interrupt routines.
456 * -------------------------------------------------------------------
457 */
458
459