diff options
| -rw-r--r-- | arch/m68k/kernel/entry.S | 11 | ||||
| -rw-r--r-- | arch/m68k/q40/config.c | 11 | ||||
| -rw-r--r-- | arch/m68k/q40/q40ints.c | 464 |
3 files changed, 169 insertions, 317 deletions
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 48cccc556e13..449b62b30f45 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S | |||
| @@ -205,18 +205,9 @@ ENTRY(auto_inthandler) | |||
| 205 | 205 | ||
| 206 | movel %sp,%sp@- | 206 | movel %sp,%sp@- |
| 207 | movel %d0,%sp@- | put vector # on stack | 207 | movel %d0,%sp@- | put vector # on stack |
| 208 | #if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD) | ||
| 209 | btstb #4,0xff000000 | Q40 floppy needs very special treatment ... | ||
| 210 | jbeq 1f | ||
| 211 | btstb #3,0xff000004 | ||
| 212 | jbeq 1f | ||
| 213 | jbsr floppy_hardint | ||
| 214 | jbra 3f | ||
| 215 | 1: | ||
| 216 | #endif | ||
| 217 | auto_irqhandler_fixup = . + 2 | 208 | auto_irqhandler_fixup = . + 2 |
| 218 | jsr m68k_handle_int | process the IRQ | 209 | jsr m68k_handle_int | process the IRQ |
| 219 | 3: addql #8,%sp | pop parameters off stack | 210 | addql #8,%sp | pop parameters off stack |
| 220 | 211 | ||
| 221 | ret_from_interrupt: | 212 | ret_from_interrupt: |
| 222 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) | 213 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) |
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index 01fd662bfada..efa52d302d67 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c | |||
| @@ -38,13 +38,8 @@ | |||
| 38 | 38 | ||
| 39 | extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); | 39 | extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); |
| 40 | extern void q40_init_IRQ (void); | 40 | extern void q40_init_IRQ (void); |
| 41 | extern void q40_free_irq (unsigned int, void *); | ||
| 42 | extern int show_q40_interrupts (struct seq_file *, void *); | ||
| 43 | extern void q40_enable_irq (unsigned int); | ||
| 44 | extern void q40_disable_irq (unsigned int); | ||
| 45 | static void q40_get_model(char *model); | 41 | static void q40_get_model(char *model); |
| 46 | static int q40_get_hardware_list(char *buffer); | 42 | static int q40_get_hardware_list(char *buffer); |
| 47 | extern int q40_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); | ||
| 48 | extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); | 43 | extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); |
| 49 | 44 | ||
| 50 | extern unsigned long q40_gettimeoffset (void); | 45 | extern unsigned long q40_gettimeoffset (void); |
| @@ -174,12 +169,6 @@ void __init config_q40(void) | |||
| 174 | mach_set_clock_mmss = q40_set_clock_mmss; | 169 | mach_set_clock_mmss = q40_set_clock_mmss; |
| 175 | 170 | ||
| 176 | mach_reset = q40_reset; | 171 | mach_reset = q40_reset; |
| 177 | mach_free_irq = q40_free_irq; | ||
| 178 | mach_process_int = q40_process_int; | ||
| 179 | mach_get_irq_list = show_q40_interrupts; | ||
| 180 | mach_request_irq = q40_request_irq; | ||
| 181 | enable_irq = q40_enable_irq; | ||
| 182 | disable_irq = q40_disable_irq; | ||
| 183 | mach_get_model = q40_get_model; | 172 | mach_get_model = q40_get_model; |
| 184 | mach_get_hardware_list = q40_get_hardware_list; | 173 | mach_get_hardware_list = q40_get_hardware_list; |
| 185 | 174 | ||
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c index ff80cba110d4..472f41c4158b 100644 --- a/arch/m68k/q40/q40ints.c +++ b/arch/m68k/q40/q40ints.c | |||
| @@ -14,13 +14,8 @@ | |||
| 14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 17 | #include <linux/string.h> | ||
| 18 | #include <linux/sched.h> | ||
| 19 | #include <linux/seq_file.h> | ||
| 20 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 21 | #include <linux/hardirq.h> | ||
| 22 | 18 | ||
| 23 | #include <asm/rtc.h> | ||
| 24 | #include <asm/ptrace.h> | 19 | #include <asm/ptrace.h> |
| 25 | #include <asm/system.h> | 20 | #include <asm/system.h> |
| 26 | #include <asm/irq.h> | 21 | #include <asm/irq.h> |
| @@ -39,28 +34,37 @@ | |||
| 39 | * | 34 | * |
| 40 | */ | 35 | */ |
| 41 | 36 | ||
| 42 | extern int ints_inited; | 37 | static void q40_irq_handler(unsigned int, struct pt_regs *fp); |
| 38 | static void q40_enable_irq(unsigned int); | ||
| 39 | static void q40_disable_irq(unsigned int); | ||
| 43 | 40 | ||
| 41 | unsigned short q40_ablecount[35]; | ||
| 42 | unsigned short q40_state[35]; | ||
| 44 | 43 | ||
| 45 | irqreturn_t q40_irq2_handler (int, void *, struct pt_regs *fp); | 44 | static int q40_irq_startup(unsigned int irq) |
| 46 | 45 | { | |
| 47 | 46 | /* test for ISA ints not implemented by HW */ | |
| 48 | static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp); | 47 | switch (irq) { |
| 49 | 48 | case 1: case 2: case 8: case 9: | |
| 50 | 49 | case 11: case 12: case 13: | |
| 51 | #define DEVNAME_SIZE 24 | 50 | printk("%s: ISA IRQ %d not implemented by HW\n", __FUNCTION__, irq); |
| 51 | return -ENXIO; | ||
| 52 | } | ||
| 53 | return 0; | ||
| 54 | } | ||
| 52 | 55 | ||
| 53 | static struct q40_irq_node { | 56 | static void q40_irq_shutdown(unsigned int irq) |
| 54 | irqreturn_t (*handler)(int, void *, struct pt_regs *); | 57 | { |
| 55 | unsigned long flags; | 58 | } |
| 56 | void *dev_id; | ||
| 57 | /* struct q40_irq_node *next;*/ | ||
| 58 | char devname[DEVNAME_SIZE]; | ||
| 59 | unsigned count; | ||
| 60 | unsigned short state; | ||
| 61 | } irq_tab[Q40_IRQ_MAX+1]; | ||
| 62 | 59 | ||
| 63 | short unsigned q40_ablecount[Q40_IRQ_MAX+1]; | 60 | static struct irq_controller q40_irq_controller = { |
| 61 | .name = "q40", | ||
| 62 | .lock = SPIN_LOCK_UNLOCKED, | ||
| 63 | .startup = q40_irq_startup, | ||
| 64 | .shutdown = q40_irq_shutdown, | ||
| 65 | .enable = q40_enable_irq, | ||
| 66 | .disable = q40_disable_irq, | ||
| 67 | }; | ||
| 64 | 68 | ||
| 65 | /* | 69 | /* |
| 66 | * void q40_init_IRQ (void) | 70 | * void q40_init_IRQ (void) |
| @@ -73,139 +77,29 @@ short unsigned q40_ablecount[Q40_IRQ_MAX+1]; | |||
| 73 | * the q40 IRQ handling routines. | 77 | * the q40 IRQ handling routines. |
| 74 | */ | 78 | */ |
| 75 | 79 | ||
| 76 | static int disabled=0; | 80 | static int disabled; |
| 77 | 81 | ||
| 78 | void q40_init_IRQ (void) | 82 | void q40_init_IRQ(void) |
| 79 | { | 83 | { |
| 80 | int i; | 84 | m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX); |
| 81 | |||
| 82 | disabled=0; | ||
| 83 | for (i = 0; i <= Q40_IRQ_MAX; i++) { | ||
| 84 | irq_tab[i].handler = q40_defhand; | ||
| 85 | irq_tab[i].flags = 0; | ||
| 86 | irq_tab[i].dev_id = NULL; | ||
| 87 | /* irq_tab[i].next = NULL;*/ | ||
| 88 | irq_tab[i].devname[0] = 0; | ||
| 89 | irq_tab[i].count = 0; | ||
| 90 | irq_tab[i].state =0; | ||
| 91 | q40_ablecount[i]=0; /* all enabled */ | ||
| 92 | } | ||
| 93 | 85 | ||
| 94 | /* setup handler for ISA ints */ | 86 | /* setup handler for ISA ints */ |
| 95 | cpu_request_irq(IRQ_AUTO_2, q40_irq2_handler, 0, | 87 | m68k_setup_auto_interrupt(q40_irq_handler); |
| 96 | "q40 ISA and master chip", NULL); | 88 | |
| 89 | m68k_irq_startup(IRQ_AUTO_2); | ||
| 90 | m68k_irq_startup(IRQ_AUTO_4); | ||
| 97 | 91 | ||
| 98 | /* now enable some ints.. */ | 92 | /* now enable some ints.. */ |
| 99 | master_outb(1,EXT_ENABLE_REG); /* ISA IRQ 5-15 */ | 93 | master_outb(1, EXT_ENABLE_REG); /* ISA IRQ 5-15 */ |
| 100 | 94 | ||
| 101 | /* make sure keyboard IRQ is disabled */ | 95 | /* make sure keyboard IRQ is disabled */ |
| 102 | master_outb(0,KEY_IRQ_ENABLE_REG); | 96 | master_outb(0, KEY_IRQ_ENABLE_REG); |
| 103 | } | 97 | } |
| 104 | 98 | ||
| 105 | int q40_request_irq(unsigned int irq, | ||
| 106 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
| 107 | unsigned long flags, const char *devname, void *dev_id) | ||
| 108 | { | ||
| 109 | /*printk("q40_request_irq %d, %s\n",irq,devname);*/ | ||
| 110 | |||
| 111 | if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) { | ||
| 112 | printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname); | ||
| 113 | return -ENXIO; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* test for ISA ints not implemented by HW */ | ||
| 117 | switch (irq) | ||
| 118 | { | ||
| 119 | case 1: case 2: case 8: case 9: | ||
| 120 | case 12: case 13: | ||
| 121 | printk("%s: ISA IRQ %d from %s not implemented by HW\n", __FUNCTION__, irq, devname); | ||
| 122 | return -ENXIO; | ||
| 123 | case 11: | ||
| 124 | printk("warning IRQ 10 and 11 not distinguishable\n"); | ||
| 125 | irq=10; | ||
| 126 | default: | ||
| 127 | ; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (irq<Q40_IRQ_SAMPLE) | ||
| 131 | { | ||
| 132 | if (irq_tab[irq].dev_id != NULL) | ||
| 133 | { | ||
| 134 | printk("%s: IRQ %d from %s is not replaceable\n", | ||
| 135 | __FUNCTION__, irq, irq_tab[irq].devname); | ||
| 136 | return -EBUSY; | ||
| 137 | } | ||
| 138 | /*printk("IRQ %d set to handler %p\n",irq,handler);*/ | ||
| 139 | if (dev_id==NULL) | ||
| 140 | { | ||
| 141 | printk("WARNING: dev_id == NULL in request_irq\n"); | ||
| 142 | dev_id=(void*)1; | ||
| 143 | } | ||
| 144 | irq_tab[irq].handler = handler; | ||
| 145 | irq_tab[irq].flags = flags; | ||
| 146 | irq_tab[irq].dev_id = dev_id; | ||
| 147 | strlcpy(irq_tab[irq].devname,devname,sizeof(irq_tab[irq].devname)); | ||
| 148 | irq_tab[irq].state = 0; | ||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | else { | ||
| 152 | /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/ | ||
| 153 | cpu_request_irq(4, handler, flags, devname, dev_id); | ||
| 154 | cpu_request_irq(6, handler, flags, devname, dev_id); | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | void q40_free_irq(unsigned int irq, void *dev_id) | ||
| 160 | { | ||
| 161 | if (irq > Q40_IRQ_MAX || (irq>15 && irq<32)) { | ||
| 162 | printk("%s: Incorrect IRQ %d, dev_id %x \n", __FUNCTION__, irq, (unsigned)dev_id); | ||
| 163 | return; | ||
| 164 | } | ||
| 165 | |||
| 166 | /* test for ISA ints not implemented by HW */ | ||
| 167 | switch (irq) | ||
| 168 | { | ||
| 169 | case 1: case 2: case 8: case 9: | ||
| 170 | case 12: case 13: | ||
| 171 | printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id); | ||
| 172 | return; | ||
| 173 | case 11: irq=10; | ||
| 174 | default: | ||
| 175 | ; | ||
| 176 | } | ||
| 177 | |||
| 178 | if (irq<Q40_IRQ_SAMPLE) | ||
| 179 | { | ||
| 180 | if (irq_tab[irq].dev_id != dev_id) | ||
| 181 | printk("%s: Removing probably wrong IRQ %d from %s\n", | ||
| 182 | __FUNCTION__, irq, irq_tab[irq].devname); | ||
| 183 | |||
| 184 | irq_tab[irq].handler = q40_defhand; | ||
| 185 | irq_tab[irq].flags = 0; | ||
| 186 | irq_tab[irq].dev_id = NULL; | ||
| 187 | /* irq_tab[irq].devname = NULL; */ | ||
| 188 | /* do not reset state !! */ | ||
| 189 | } | ||
| 190 | else | ||
| 191 | { /* == Q40_IRQ_SAMPLE */ | ||
| 192 | cpu_free_irq(4, dev_id); | ||
| 193 | cpu_free_irq(6, dev_id); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | |||
| 198 | irqreturn_t q40_process_int (int level, struct pt_regs *fp) | ||
| 199 | { | ||
| 200 | printk("unexpected interrupt vec=%x, pc=%lx, d0=%lx, d0_orig=%lx, d1=%lx, d2=%lx\n", | ||
| 201 | level, fp->pc, fp->d0, fp->orig_d0, fp->d1, fp->d2); | ||
| 202 | printk("\tIIRQ_REG = %x, EIRQ_REG = %x\n",master_inb(IIRQ_REG),master_inb(EIRQ_REG)); | ||
| 203 | return IRQ_HANDLED; | ||
| 204 | } | ||
| 205 | 99 | ||
| 206 | /* | 100 | /* |
| 207 | * this stuff doesn't really belong here.. | 101 | * this stuff doesn't really belong here.. |
| 208 | */ | 102 | */ |
| 209 | 103 | ||
| 210 | int ql_ticks; /* 200Hz ticks since last jiffie */ | 104 | int ql_ticks; /* 200Hz ticks since last jiffie */ |
| 211 | static int sound_ticks; | 105 | static int sound_ticks; |
| @@ -214,54 +108,53 @@ static int sound_ticks; | |||
| 214 | 108 | ||
| 215 | void q40_mksound(unsigned int hz, unsigned int ticks) | 109 | void q40_mksound(unsigned int hz, unsigned int ticks) |
| 216 | { | 110 | { |
| 217 | /* for now ignore hz, except that hz==0 switches off sound */ | 111 | /* for now ignore hz, except that hz==0 switches off sound */ |
| 218 | /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */ | 112 | /* simply alternate the ampl (128-SVOL)-(128+SVOL)-..-.. at 200Hz */ |
| 219 | if (hz==0) | 113 | if (hz == 0) { |
| 220 | { | 114 | if (sound_ticks) |
| 221 | if (sound_ticks) | 115 | sound_ticks = 1; |
| 222 | sound_ticks=1; | 116 | |
| 223 | 117 | *DAC_LEFT = 128; | |
| 224 | *DAC_LEFT=128; | 118 | *DAC_RIGHT = 128; |
| 225 | *DAC_RIGHT=128; | 119 | |
| 226 | 120 | return; | |
| 227 | return; | 121 | } |
| 228 | } | 122 | /* sound itself is done in q40_timer_int */ |
| 229 | /* sound itself is done in q40_timer_int */ | 123 | if (sound_ticks == 0) |
| 230 | if (sound_ticks == 0) sound_ticks=1000; /* pretty long beep */ | 124 | sound_ticks = 1000; /* pretty long beep */ |
| 231 | sound_ticks=ticks<<1; | 125 | sound_ticks = ticks << 1; |
| 232 | } | 126 | } |
| 233 | 127 | ||
| 234 | static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *); | 128 | static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *); |
| 235 | 129 | ||
| 236 | static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs) | 130 | static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs) |
| 237 | { | 131 | { |
| 238 | ql_ticks = ql_ticks ? 0 : 1; | 132 | ql_ticks = ql_ticks ? 0 : 1; |
| 239 | if (sound_ticks) | 133 | if (sound_ticks) { |
| 240 | { | 134 | unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; |
| 241 | unsigned char sval=(sound_ticks & 1) ? 128-SVOL : 128+SVOL; | 135 | sound_ticks--; |
| 242 | sound_ticks--; | 136 | *DAC_LEFT=sval; |
| 243 | *DAC_LEFT=sval; | 137 | *DAC_RIGHT=sval; |
| 244 | *DAC_RIGHT=sval; | 138 | } |
| 245 | } | 139 | |
| 246 | 140 | if (!ql_ticks) | |
| 247 | if (!ql_ticks) | 141 | q40_timer_routine(irq, dev, regs); |
| 248 | q40_timer_routine(irq, dev, regs); | 142 | return IRQ_HANDLED; |
| 249 | return IRQ_HANDLED; | ||
| 250 | } | 143 | } |
| 251 | 144 | ||
| 252 | void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) | 145 | void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) |
| 253 | { | 146 | { |
| 254 | int timer_irq; | 147 | int timer_irq; |
| 255 | 148 | ||
| 256 | q40_timer_routine = timer_routine; | 149 | q40_timer_routine = timer_routine; |
| 257 | timer_irq=Q40_IRQ_FRAME; | 150 | timer_irq = Q40_IRQ_FRAME; |
| 258 | 151 | ||
| 259 | if (request_irq(timer_irq, q40_timer_int, 0, | 152 | if (request_irq(timer_irq, q40_timer_int, 0, |
| 260 | "timer", q40_timer_int)) | 153 | "timer", q40_timer_int)) |
| 261 | panic ("Couldn't register timer int"); | 154 | panic("Couldn't register timer int"); |
| 262 | 155 | ||
| 263 | master_outb(-1,FRAME_CLEAR_REG); | 156 | master_outb(-1, FRAME_CLEAR_REG); |
| 264 | master_outb( 1,FRAME_RATE_REG); | 157 | master_outb( 1, FRAME_RATE_REG); |
| 265 | } | 158 | } |
| 266 | 159 | ||
| 267 | 160 | ||
| @@ -307,153 +200,132 @@ static int mext_disabled=0; /* ext irq disabled by master chip? */ | |||
| 307 | static int aliased_irq=0; /* how many times inside handler ?*/ | 200 | static int aliased_irq=0; /* how many times inside handler ?*/ |
| 308 | 201 | ||
| 309 | 202 | ||
| 310 | /* got level 2 interrupt, dispatch to ISA or keyboard/timer IRQs */ | 203 | /* got interrupt, dispatch to ISA or keyboard/timer IRQs */ |
| 311 | irqreturn_t q40_irq2_handler (int vec, void *devname, struct pt_regs *fp) | 204 | static void q40_irq_handler(unsigned int irq, struct pt_regs *fp) |
| 312 | { | 205 | { |
| 313 | unsigned mir, mer; | 206 | unsigned mir, mer; |
| 314 | int irq,i; | 207 | int i; |
| 315 | 208 | ||
| 316 | //repeat: | 209 | //repeat: |
| 317 | mir=master_inb(IIRQ_REG); | 210 | mir = master_inb(IIRQ_REG); |
| 318 | if (mir&Q40_IRQ_FRAME_MASK) { | 211 | #ifdef CONFIG_BLK_DEV_FD |
| 319 | irq_tab[Q40_IRQ_FRAME].count++; | 212 | if ((mir & Q40_IRQ_EXT_MASK) && |
| 320 | irq_tab[Q40_IRQ_FRAME].handler(Q40_IRQ_FRAME,irq_tab[Q40_IRQ_FRAME].dev_id,fp); | 213 | (master_inb(EIRQ_REG) & Q40_IRQ6_MASK)) { |
| 321 | master_outb(-1,FRAME_CLEAR_REG); | 214 | floppy_hardint(); |
| 322 | } | 215 | return; |
| 323 | if ((mir&Q40_IRQ_SER_MASK) || (mir&Q40_IRQ_EXT_MASK)) { | 216 | } |
| 324 | mer=master_inb(EIRQ_REG); | 217 | #endif |
| 325 | for (i=0; eirqs[i].mask; i++) { | 218 | switch (irq) { |
| 326 | if (mer&(eirqs[i].mask)) { | 219 | case 4: |
| 327 | irq=eirqs[i].irq; | 220 | case 6: |
| 221 | m68k_handle_int(Q40_IRQ_SAMPLE, fp); | ||
| 222 | return; | ||
| 223 | } | ||
| 224 | if (mir & Q40_IRQ_FRAME_MASK) { | ||
| 225 | m68k_handle_int(Q40_IRQ_FRAME, fp); | ||
| 226 | master_outb(-1, FRAME_CLEAR_REG); | ||
| 227 | } | ||
| 228 | if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) { | ||
| 229 | mer = master_inb(EIRQ_REG); | ||
| 230 | for (i = 0; eirqs[i].mask; i++) { | ||
| 231 | if (mer & eirqs[i].mask) { | ||
| 232 | irq = eirqs[i].irq; | ||
| 328 | /* | 233 | /* |
| 329 | * There is a little mess wrt which IRQ really caused this irq request. The | 234 | * There is a little mess wrt which IRQ really caused this irq request. The |
| 330 | * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they | 235 | * main problem is that IIRQ_REG and EIRQ_REG reflect the state when they |
| 331 | * are read - which is long after the request came in. In theory IRQs should | 236 | * are read - which is long after the request came in. In theory IRQs should |
| 332 | * not just go away but they occassionally do | 237 | * not just go away but they occassionally do |
| 333 | */ | 238 | */ |
| 334 | if (irq>4 && irq<=15 && mext_disabled) { | 239 | if (irq > 4 && irq <= 15 && mext_disabled) { |
| 335 | /*aliased_irq++;*/ | 240 | /*aliased_irq++;*/ |
| 336 | goto iirq; | 241 | goto iirq; |
| 337 | } | 242 | } |
| 338 | if (irq_tab[irq].handler == q40_defhand ) { | 243 | if (q40_state[irq] & IRQ_INPROGRESS) { |
| 339 | printk("handler for IRQ %d not defined\n",irq); | 244 | /* some handlers do local_irq_enable() for irq latency reasons, */ |
| 340 | continue; /* ignore uninited INTs :-( */ | 245 | /* however reentering an active irq handler is not permitted */ |
| 341 | } | ||
| 342 | if ( irq_tab[irq].state & IRQ_INPROGRESS ) { | ||
| 343 | /* some handlers do local_irq_enable() for irq latency reasons, */ | ||
| 344 | /* however reentering an active irq handler is not permitted */ | ||
| 345 | #ifdef IP_USE_DISABLE | 246 | #ifdef IP_USE_DISABLE |
| 346 | /* in theory this is the better way to do it because it still */ | 247 | /* in theory this is the better way to do it because it still */ |
| 347 | /* lets through eg the serial irqs, unfortunately it crashes */ | 248 | /* lets through eg the serial irqs, unfortunately it crashes */ |
| 348 | disable_irq(irq); | 249 | disable_irq(irq); |
| 349 | disabled=1; | 250 | disabled = 1; |
| 350 | #else | 251 | #else |
| 351 | /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n",irq,disabled ? "already" : "not yet"); */ | 252 | /*printk("IRQ_INPROGRESS detected for irq %d, disabling - %s disabled\n", |
| 352 | fp->sr = (((fp->sr) & (~0x700))+0x200); | 253 | irq, disabled ? "already" : "not yet"); */ |
| 353 | disabled=1; | 254 | fp->sr = (((fp->sr) & (~0x700))+0x200); |
| 255 | disabled = 1; | ||
| 354 | #endif | 256 | #endif |
| 355 | goto iirq; | 257 | goto iirq; |
| 356 | } | 258 | } |
| 357 | irq_tab[irq].count++; | 259 | q40_state[irq] |= IRQ_INPROGRESS; |
| 358 | irq_tab[irq].state |= IRQ_INPROGRESS; | 260 | m68k_handle_int(irq, fp); |
| 359 | irq_tab[irq].handler(irq,irq_tab[irq].dev_id,fp); | 261 | q40_state[irq] &= ~IRQ_INPROGRESS; |
| 360 | irq_tab[irq].state &= ~IRQ_INPROGRESS; | 262 | |
| 361 | 263 | /* naively enable everything, if that fails than */ | |
| 362 | /* naively enable everything, if that fails than */ | 264 | /* this function will be reentered immediately thus */ |
| 363 | /* this function will be reentered immediately thus */ | 265 | /* getting another chance to disable the IRQ */ |
| 364 | /* getting another chance to disable the IRQ */ | 266 | |
| 365 | 267 | if (disabled) { | |
| 366 | if ( disabled ) { | ||
| 367 | #ifdef IP_USE_DISABLE | 268 | #ifdef IP_USE_DISABLE |
| 368 | if (irq>4){ | 269 | if (irq > 4) { |
| 369 | disabled=0; | 270 | disabled = 0; |
| 370 | enable_irq(irq);} | 271 | enable_irq(irq); |
| 272 | } | ||
| 371 | #else | 273 | #else |
| 372 | disabled=0; | 274 | disabled = 0; |
| 373 | /*printk("reenabling irq %d\n",irq); */ | 275 | /*printk("reenabling irq %d\n", irq); */ |
| 374 | #endif | 276 | #endif |
| 375 | } | 277 | } |
| 376 | // used to do 'goto repeat;' here, this delayed bh processing too long | 278 | // used to do 'goto repeat;' here, this delayed bh processing too long |
| 377 | return IRQ_HANDLED; | 279 | return; |
| 378 | } | 280 | } |
| 379 | } | 281 | } |
| 380 | if (mer && ccleirq>0 && !aliased_irq) | 282 | if (mer && ccleirq > 0 && !aliased_irq) { |
| 381 | printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer),ccleirq--; | 283 | printk("ISA interrupt from unknown source? EIRQ_REG = %x\n",mer); |
| 382 | } | 284 | ccleirq--; |
| 383 | iirq: | 285 | } |
| 384 | mir=master_inb(IIRQ_REG); | ||
| 385 | /* should test whether keyboard irq is really enabled, doing it in defhand */ | ||
| 386 | if (mir&Q40_IRQ_KEYB_MASK) { | ||
| 387 | irq_tab[Q40_IRQ_KEYBOARD].count++; | ||
| 388 | irq_tab[Q40_IRQ_KEYBOARD].handler(Q40_IRQ_KEYBOARD,irq_tab[Q40_IRQ_KEYBOARD].dev_id,fp); | ||
| 389 | } | ||
| 390 | return IRQ_HANDLED; | ||
| 391 | } | ||
| 392 | |||
| 393 | int show_q40_interrupts (struct seq_file *p, void *v) | ||
| 394 | { | ||
| 395 | int i; | ||
| 396 | |||
| 397 | for (i = 0; i <= Q40_IRQ_MAX; i++) { | ||
| 398 | if (irq_tab[i].count) | ||
| 399 | seq_printf(p, "%sIRQ %02d: %8d %s%s\n", | ||
| 400 | (i<=15) ? "ISA-" : " " , | ||
| 401 | i, irq_tab[i].count, | ||
| 402 | irq_tab[i].devname[0] ? irq_tab[i].devname : "?", | ||
| 403 | irq_tab[i].handler == q40_defhand ? | ||
| 404 | " (now unassigned)" : ""); | ||
| 405 | } | 286 | } |
| 406 | return 0; | 287 | iirq: |
| 407 | } | 288 | mir = master_inb(IIRQ_REG); |
| 408 | 289 | /* should test whether keyboard irq is really enabled, doing it in defhand */ | |
| 290 | if (mir & Q40_IRQ_KEYB_MASK) | ||
| 291 | m68k_handle_int(Q40_IRQ_KEYBOARD, fp); | ||
| 409 | 292 | ||
| 410 | static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp) | 293 | return; |
| 411 | { | ||
| 412 | if (irq!=Q40_IRQ_KEYBOARD) | ||
| 413 | printk ("Unknown q40 interrupt %d\n", irq); | ||
| 414 | else master_outb(-1,KEYBOARD_UNLOCK_REG); | ||
| 415 | return IRQ_NONE; | ||
| 416 | } | 294 | } |
| 417 | 295 | ||
| 418 | 296 | void q40_enable_irq(unsigned int irq) | |
| 419 | void q40_enable_irq (unsigned int irq) | ||
| 420 | { | 297 | { |
| 421 | if ( irq>=5 && irq<=15 ) | 298 | if (irq >= 5 && irq <= 15) { |
| 422 | { | 299 | mext_disabled--; |
| 423 | mext_disabled--; | 300 | if (mext_disabled > 0) |
| 424 | if (mext_disabled>0) | 301 | printk("q40_enable_irq : nested disable/enable\n"); |
| 425 | printk("q40_enable_irq : nested disable/enable\n"); | 302 | if (mext_disabled == 0) |
| 426 | if (mext_disabled==0) | 303 | master_outb(1, EXT_ENABLE_REG); |
| 427 | master_outb(1,EXT_ENABLE_REG); | 304 | } |
| 428 | } | ||
| 429 | } | 305 | } |
| 430 | 306 | ||
| 431 | 307 | ||
| 432 | void q40_disable_irq (unsigned int irq) | 308 | void q40_disable_irq(unsigned int irq) |
| 433 | { | 309 | { |
| 434 | /* disable ISA iqs : only do something if the driver has been | 310 | /* disable ISA iqs : only do something if the driver has been |
| 435 | * verified to be Q40 "compatible" - right now IDE, NE2K | 311 | * verified to be Q40 "compatible" - right now IDE, NE2K |
| 436 | * Any driver should not attempt to sleep across disable_irq !! | 312 | * Any driver should not attempt to sleep across disable_irq !! |
| 437 | */ | 313 | */ |
| 438 | 314 | ||
| 439 | if ( irq>=5 && irq<=15 ) { | 315 | if (irq >= 5 && irq <= 15) { |
| 440 | master_outb(0,EXT_ENABLE_REG); | 316 | master_outb(0, EXT_ENABLE_REG); |
| 441 | mext_disabled++; | 317 | mext_disabled++; |
| 442 | if (mext_disabled>1) printk("disable_irq nesting count %d\n",mext_disabled); | 318 | if (mext_disabled > 1) |
| 443 | } | 319 | printk("disable_irq nesting count %d\n",mext_disabled); |
| 320 | } | ||
| 444 | } | 321 | } |
| 445 | 322 | ||
| 446 | unsigned long q40_probe_irq_on (void) | 323 | unsigned long q40_probe_irq_on(void) |
| 447 | { | 324 | { |
| 448 | printk("irq probing not working - reconfigure the driver to avoid this\n"); | 325 | printk("irq probing not working - reconfigure the driver to avoid this\n"); |
| 449 | return -1; | 326 | return -1; |
| 450 | } | 327 | } |
| 451 | int q40_probe_irq_off (unsigned long irqs) | 328 | int q40_probe_irq_off(unsigned long irqs) |
| 452 | { | 329 | { |
| 453 | return -1; | 330 | return -1; |
| 454 | } | 331 | } |
| 455 | /* | ||
| 456 | * Local variables: | ||
| 457 | * compile-command: "m68k-linux-gcc -D__KERNEL__ -I/home/rz/lx/linux-2.2.6/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -m68040 -c -o q40ints.o q40ints.c" | ||
| 458 | * End: | ||
| 459 | */ | ||
