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