root/arch/m68k/q40/q40ints.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. q40_irq_startup
  2. q40_irq_shutdown
  3. q40_init_IRQ
  4. q40_mksound
  5. q40_timer_int
  6. q40_sched_init
  7. q40_irq_handler
  8. q40_irq_enable
  9. q40_irq_disable

   1 /*
   2  * arch/m68k/q40/q40ints.c
   3  *
   4  * Copyright (C) 1999,2001 Richard Zidlicky
   5  *
   6  * This file is subject to the terms and conditions of the GNU General Public
   7  * License.  See the file COPYING in the main directory of this archive
   8  * for more details.
   9  *
  10  * .. used to be loosely based on bvme6000ints.c
  11  *
  12  */
  13 
  14 #include <linux/types.h>
  15 #include <linux/kernel.h>
  16 #include <linux/errno.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/irq.h>
  19 
  20 #include <asm/ptrace.h>
  21 #include <asm/traps.h>
  22 
  23 #include <asm/q40_master.h>
  24 #include <asm/q40ints.h>
  25 
  26 /*
  27  * Q40 IRQs are defined as follows:
  28  *            3,4,5,6,7,10,11,14,15 : ISA dev IRQs
  29  *            16-31: reserved
  30  *            32   : keyboard int
  31  *            33   : frame int (50/200 Hz periodic timer)
  32  *            34   : sample int (10/20 KHz periodic timer)
  33  *
  34 */
  35 
  36 static void q40_irq_handler(unsigned int, struct pt_regs *fp);
  37 static void q40_irq_enable(struct irq_data *data);
  38 static void q40_irq_disable(struct irq_data *data);
  39 
  40 unsigned short q40_ablecount[35];
  41 unsigned short q40_state[35];
  42 
  43 static unsigned int q40_irq_startup(struct irq_data *data)
  44 {
  45         unsigned int irq = data->irq;
  46 
  47         /* test for ISA ints not implemented by HW */
  48         switch (irq) {
  49         case 1: case 2: case 8: case 9:
  50         case 11: case 12: case 13:
  51                 pr_warn("%s: ISA IRQ %d not implemented by HW\n", __func__,
  52                         irq);
  53                 /* FIXME return -ENXIO; */
  54         }
  55         return 0;
  56 }
  57 
  58 static void q40_irq_shutdown(struct irq_data *data)
  59 {
  60 }
  61 
  62 static struct irq_chip q40_irq_chip = {
  63         .name           = "q40",
  64         .irq_startup    = q40_irq_startup,
  65         .irq_shutdown   = q40_irq_shutdown,
  66         .irq_enable     = q40_irq_enable,
  67         .irq_disable    = q40_irq_disable,
  68 };
  69 
  70 /*
  71  * void q40_init_IRQ (void)
  72  *
  73  * Parameters:  None
  74  *
  75  * Returns:     Nothing
  76  *
  77  * This function is called during kernel startup to initialize
  78  * the q40 IRQ handling routines.
  79  */
  80 
  81 static int disabled;
  82 
  83 void __init q40_init_IRQ(void)
  84 {
  85         m68k_setup_irq_controller(&q40_irq_chip, handle_simple_irq, 1,
  86                                   Q40_IRQ_MAX);
  87 
  88         /* setup handler for ISA ints */
  89         m68k_setup_auto_interrupt(q40_irq_handler);
  90 
  91         m68k_irq_startup_irq(IRQ_AUTO_2);
  92         m68k_irq_startup_irq(IRQ_AUTO_4);
  93 
  94         /* now enable some ints.. */
  95         master_outb(1, EXT_ENABLE_REG);  /* ISA IRQ 5-15 */
  96 
  97         /* make sure keyboard IRQ is disabled */
  98         master_outb(0, KEY_IRQ_ENABLE_REG);
  99 }
 100 
 101 
 102 /*
 103  * this stuff doesn't really belong here..
 104  */
 105 
 106 int ql_ticks;              /* 200Hz ticks since last jiffie */
 107 static int sound_ticks;
 108 
 109 #define SVOL 45
 110 
 111 void q40_mksound(unsigned int hz, unsigned int ticks)
 112 {
 113         /* for now ignore hz, except that hz==0 switches off sound */
 114         /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */
 115         if (hz == 0) {
 116                 if (sound_ticks)
 117                         sound_ticks = 1;
 118 
 119                 *DAC_LEFT = 128;
 120                 *DAC_RIGHT = 128;
 121 
 122                 return;
 123         }
 124         /* sound itself is done in q40_timer_int */
 125         if (sound_ticks == 0)
 126                 sound_ticks = 1000; /* pretty long beep */
 127         sound_ticks = ticks << 1;
 128 }
 129 
 130 static irqreturn_t q40_timer_int(int irq, void *dev_id)
 131 {
 132         irq_handler_t timer_routine = dev_id;
 133 
 134         ql_ticks = ql_ticks ? 0 : 1;
 135         if (sound_ticks) {
 136                 unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL;
 137                 sound_ticks--;
 138                 *DAC_LEFT=sval;
 139                 *DAC_RIGHT=sval;
 140         }
 141 
 142         if (!ql_ticks) {
 143                 unsigned long flags;
 144 
 145                 local_irq_save(flags);
 146                 timer_routine(0, NULL);
 147                 local_irq_restore(flags);
 148         }
 149         return IRQ_HANDLED;
 150 }
 151 
 152 void q40_sched_init (irq_handler_t timer_routine)
 153 {
 154         int timer_irq;
 155 
 156         timer_irq = Q40_IRQ_FRAME;
 157 
 158         if (request_irq(timer_irq, q40_timer_int, 0, "timer", timer_routine))
 159                 panic("Couldn't register timer int");
 160 
 161         master_outb(-1, FRAME_CLEAR_REG);
 162         master_outb( 1, FRAME_RATE_REG);
 163 }
 164 
 165 
 166 /*
 167  * tables to translate bits into IRQ numbers
 168  * it is a good idea to order the entries by priority
 169  *
 170 */
 171 
 172 struct IRQ_TABLE{ unsigned mask; int irq ;};
 173 #if 0
 174 static struct IRQ_TABLE iirqs[]={
 175   {Q40_IRQ_FRAME_MASK,Q40_IRQ_FRAME},
 176   {Q40_IRQ_KEYB_MASK,Q40_IRQ_KEYBOARD},
 177   {0,0}};
 178 #endif
 179 static struct IRQ_TABLE eirqs[] = {
 180   { .mask = Q40_IRQ3_MASK,      .irq = 3 },     /* ser 1 */
 181   { .mask = Q40_IRQ4_MASK,      .irq = 4 },     /* ser 2 */
 182   { .mask = Q40_IRQ14_MASK,     .irq = 14 },    /* IDE 1 */
 183   { .mask = Q40_IRQ15_MASK,     .irq = 15 },    /* IDE 2 */
 184   { .mask = Q40_IRQ6_MASK,      .irq = 6 },     /* floppy, handled elsewhere */
 185   { .mask = Q40_IRQ7_MASK,      .irq = 7 },     /* par */
 186   { .mask = Q40_IRQ5_MASK,      .irq = 5 },
 187   { .mask = Q40_IRQ10_MASK,     .irq = 10 },
 188   {0,0}
 189 };
 190 
 191 /* complain only this many times about spurious ints : */
 192 static int ccleirq=60;    /* ISA dev IRQs*/
 193 /*static int cclirq=60;*/     /* internal */
 194 
 195 /* FIXME: add shared ints,mask,unmask,probing.... */
 196 
 197 #define IRQ_INPROGRESS 1
 198 /*static unsigned short saved_mask;*/
 199 //static int do_tint=0;
 200 
 201 #define DEBUG_Q40INT
 202 /*#define IP_USE_DISABLE *//* would be nice, but crashes ???? */
 203 
 204 static int mext_disabled=0;  /* ext irq disabled by master chip? */
 205 static int aliased_irq=0;  /* how many times inside handler ?*/
 206 
 207 
 208 /* got interrupt, dispatch to ISA or keyboard/timer IRQs */
 209 static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
 210 {
 211         unsigned mir, mer;
 212         int i;
 213 
 214 //repeat:
 215         mir = master_inb(IIRQ_REG);
 216 #ifdef CONFIG_BLK_DEV_FD
 217         if ((mir & Q40_IRQ_EXT_MASK) &&
 218             (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) {
 219                 floppy_hardint();
 220                 return;
 221         }
 222 #endif
 223         switch (irq) {
 224         case 4:
 225         case 6:
 226                 do_IRQ(Q40_IRQ_SAMPLE, fp);
 227                 return;
 228         }
 229         if (mir & Q40_IRQ_FRAME_MASK) {
 230                 do_IRQ(Q40_IRQ_FRAME, fp);
 231                 master_outb(-1, FRAME_CLEAR_REG);
 232         }
 233         if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
 234                 mer = master_inb(EIRQ_REG);
 235                 for (i = 0; eirqs[i].mask; i++) {
 236                         if (mer & eirqs[i].mask) {
 237                                 irq = eirqs[i].irq;
 238 /*
 239  * There is a little mess wrt which IRQ really caused this irq request. The
 240  * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they
 241  * are read - which is long after the request came in. In theory IRQs should
 242  * not just go away but they occasionally do
 243  */
 244                                 if (irq > 4 && irq <= 15 && mext_disabled) {
 245                                         /*aliased_irq++;*/
 246                                         goto iirq;
 247                                 }
 248                                 if (q40_state[irq] & IRQ_INPROGRESS) {
 249                                         /* some handlers do local_irq_enable() for irq latency reasons, */
 250                                         /* however reentering an active irq handler is not permitted */
 251 #ifdef IP_USE_DISABLE
 252                                         /* in theory this is the better way to do it because it still */
 253                                         /* lets through eg the serial irqs, unfortunately it crashes */
 254                                         disable_irq(irq);
 255                                         disabled = 1;
 256 #else
 257                                         /*pr_warn("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",
 258                                                 irq, disabled ? "already" : "not yet"); */
 259                                         fp->sr = (((fp->sr) & (~0x700))+0x200);
 260                                         disabled = 1;
 261 #endif
 262                                         goto iirq;
 263                                 }
 264                                 q40_state[irq] |= IRQ_INPROGRESS;
 265                                 do_IRQ(irq, fp);
 266                                 q40_state[irq] &= ~IRQ_INPROGRESS;
 267 
 268                                 /* naively enable everything, if that fails than    */
 269                                 /* this function will be reentered immediately thus */
 270                                 /* getting another chance to disable the IRQ        */
 271 
 272                                 if (disabled) {
 273 #ifdef IP_USE_DISABLE
 274                                         if (irq > 4) {
 275                                                 disabled = 0;
 276                                                 enable_irq(irq);
 277                                         }
 278 #else
 279                                         disabled = 0;
 280                                         /*pr_info("reenabling irq %d\n", irq); */
 281 #endif
 282                                 }
 283 // used to do 'goto repeat;' here, this delayed bh processing too long
 284                                 return;
 285                         }
 286                 }
 287                 if (mer && ccleirq > 0 && !aliased_irq) {
 288                         pr_warn("ISA interrupt from unknown source? EIRQ_REG = %x\n",
 289                                 mer);
 290                         ccleirq--;
 291                 }
 292         }
 293  iirq:
 294         mir = master_inb(IIRQ_REG);
 295         /* should test whether keyboard irq is really enabled, doing it in defhand */
 296         if (mir & Q40_IRQ_KEYB_MASK)
 297                 do_IRQ(Q40_IRQ_KEYBOARD, fp);
 298 
 299         return;
 300 }
 301 
 302 void q40_irq_enable(struct irq_data *data)
 303 {
 304         unsigned int irq = data->irq;
 305 
 306         if (irq >= 5 && irq <= 15) {
 307                 mext_disabled--;
 308                 if (mext_disabled > 0)
 309                         pr_warn("q40_irq_enable : nested disable/enable\n");
 310                 if (mext_disabled == 0)
 311                         master_outb(1, EXT_ENABLE_REG);
 312         }
 313 }
 314 
 315 
 316 void q40_irq_disable(struct irq_data *data)
 317 {
 318         unsigned int irq = data->irq;
 319 
 320         /* disable ISA iqs : only do something if the driver has been
 321          * verified to be Q40 "compatible" - right now IDE, NE2K
 322          * Any driver should not attempt to sleep across disable_irq !!
 323          */
 324 
 325         if (irq >= 5 && irq <= 15) {
 326                 master_outb(0, EXT_ENABLE_REG);
 327                 mext_disabled++;
 328                 if (mext_disabled > 1)
 329                         pr_info("disable_irq nesting count %d\n",
 330                                 mext_disabled);
 331         }
 332 }

/* [<][>][^][v][top][bottom][index][help] */