Annotation of Gnu-Mach/linux/src/arch/i386/kernel/irq.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  *     linux/arch/i386/kernel/irq.c
                      3:  *
                      4:  *     Copyright (C) 1992 Linus Torvalds
                      5:  *
                      6:  * This file contains the code used by various IRQ handling routines:
                      7:  * asking for different IRQ's should be done through these routines
                      8:  * instead of just grabbing them. Thus setups with different IRQ numbers
                      9:  * shouldn't result in any weird surprises, and installing new handlers
                     10:  * should be easier.
                     11:  */
                     12: 
                     13: /*
                     14:  * IRQ's are in fact implemented a bit like signal handlers for the kernel.
                     15:  * Naturally it's not a 1:1 relation, but there are similarities.
                     16:  */
                     17: 
                     18: #include <linux/ptrace.h>
                     19: #include <linux/errno.h>
                     20: #include <linux/kernel_stat.h>
                     21: #include <linux/signal.h>
                     22: #include <linux/sched.h>
                     23: #include <linux/ioport.h>
                     24: #include <linux/interrupt.h>
                     25: #include <linux/timex.h>
                     26: #include <linux/malloc.h>
                     27: #include <linux/random.h>
                     28: 
                     29: #include <asm/system.h>
                     30: #include <asm/io.h>
                     31: #include <asm/irq.h>
                     32: #include <asm/bitops.h>
                     33: #include <asm/smp.h>
                     34: 
                     35: #define CR0_NE 32
                     36: 
                     37: static unsigned char cache_21 = 0xff;
                     38: static unsigned char cache_A1 = 0xff;
                     39: 
                     40: #ifdef __SMP_PROF__
                     41: static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
                     42: #endif
                     43: 
                     44: static inline void mask_irq(unsigned int irq_nr)
                     45: {
                     46:        unsigned char mask;
                     47: 
                     48:        mask = 1 << (irq_nr & 7);
                     49:        if (irq_nr < 8) {
                     50:                cache_21 |= mask;
                     51:                outb(cache_21,0x21);
                     52:        } else {
                     53:                cache_A1 |= mask;
                     54:                outb(cache_A1,0xA1);
                     55:        }
                     56: }
                     57: 
                     58: static inline void unmask_irq(unsigned int irq_nr)
                     59: {
                     60:        unsigned char mask;
                     61: 
                     62:        mask = ~(1 << (irq_nr & 7));
                     63:        if (irq_nr < 8) {
                     64:                cache_21 &= mask;
                     65:                outb(cache_21,0x21);
                     66:        } else {
                     67:                cache_A1 &= mask;
                     68:                outb(cache_A1,0xA1);
                     69:        }
                     70: }
                     71: 
                     72: void disable_irq(unsigned int irq_nr)
                     73: {
                     74:        unsigned long flags;
                     75: 
                     76:        save_flags(flags);
                     77:        cli();
                     78:        mask_irq(irq_nr);
                     79:        restore_flags(flags);
                     80: }
                     81: 
                     82: void enable_irq(unsigned int irq_nr)
                     83: {
                     84:        unsigned long flags;
                     85:        save_flags(flags);
                     86:        cli();
                     87:        unmask_irq(irq_nr);
                     88:        restore_flags(flags);
                     89: }
                     90: 
                     91: /*
                     92:  * This builds up the IRQ handler stubs using some ugly macros in irq.h
                     93:  *
                     94:  * These macros create the low-level assembly IRQ routines that do all
                     95:  * the operations that are needed to keep the AT interrupt-controller
                     96:  * happy. They are also written to be fast - and to disable interrupts
                     97:  * as little as humanly possible.
                     98:  *
                     99:  * NOTE! These macros expand to three different handlers for each line: one
                    100:  * complete handler that does all the fancy stuff (including signal handling),
                    101:  * and one fast handler that is meant for simple IRQ's that want to be
                    102:  * atomic. The specific handler is chosen depending on the SA_INTERRUPT
                    103:  * flag when installing a handler. Finally, one "bad interrupt" handler, that
                    104:  * is used when no handler is present.
                    105:  *
                    106:  * The timer interrupt is handled specially to insure that the jiffies
                    107:  * variable is updated at all times.  Specifically, the timer interrupt is
                    108:  * just like the complete handlers except that it is invoked with interrupts
                    109:  * disabled and should never re-enable them.  If other interrupts were
                    110:  * allowed to be processed while the timer interrupt is active, then the
                    111:  * other interrupts would have to avoid using the jiffies variable for delay
                    112:  * and interval timing operations to avoid hanging the system.
                    113:  */
                    114: BUILD_TIMER_IRQ(FIRST,0,0x01)
                    115: BUILD_IRQ(FIRST,1,0x02)
                    116: BUILD_IRQ(FIRST,2,0x04)
                    117: BUILD_IRQ(FIRST,3,0x08)
                    118: BUILD_IRQ(FIRST,4,0x10)
                    119: BUILD_IRQ(FIRST,5,0x20)
                    120: BUILD_IRQ(FIRST,6,0x40)
                    121: BUILD_IRQ(FIRST,7,0x80)
                    122: BUILD_IRQ(SECOND,8,0x01)
                    123: BUILD_IRQ(SECOND,9,0x02)
                    124: BUILD_IRQ(SECOND,10,0x04)
                    125: BUILD_IRQ(SECOND,11,0x08)
                    126: BUILD_IRQ(SECOND,12,0x10)
                    127: #ifdef __SMP__
                    128: BUILD_MSGIRQ(SECOND,13,0x20)
                    129: #else
                    130: BUILD_IRQ(SECOND,13,0x20)
                    131: #endif
                    132: BUILD_IRQ(SECOND,14,0x40)
                    133: BUILD_IRQ(SECOND,15,0x80)
                    134: #ifdef __SMP__
                    135: BUILD_RESCHEDIRQ(16)
                    136: #endif
                    137: 
                    138: /*
                    139:  * Pointers to the low-level handlers: first the general ones, then the
                    140:  * fast ones, then the bad ones.
                    141:  */
                    142: static void (*interrupt[17])(void) = {
                    143:        IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt,
                    144:        IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt,
                    145:        IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt,
                    146:        IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt      
                    147: #ifdef __SMP__ 
                    148:        ,IRQ16_interrupt
                    149: #endif
                    150: };
                    151: 
                    152: static void (*fast_interrupt[16])(void) = {
                    153:        fast_IRQ0_interrupt, fast_IRQ1_interrupt,
                    154:        fast_IRQ2_interrupt, fast_IRQ3_interrupt,
                    155:        fast_IRQ4_interrupt, fast_IRQ5_interrupt,
                    156:        fast_IRQ6_interrupt, fast_IRQ7_interrupt,
                    157:        fast_IRQ8_interrupt, fast_IRQ9_interrupt,
                    158:        fast_IRQ10_interrupt, fast_IRQ11_interrupt,
                    159:        fast_IRQ12_interrupt, fast_IRQ13_interrupt,
                    160:        fast_IRQ14_interrupt, fast_IRQ15_interrupt
                    161: };
                    162: 
                    163: static void (*bad_interrupt[16])(void) = {
                    164:        bad_IRQ0_interrupt, bad_IRQ1_interrupt,
                    165:        bad_IRQ2_interrupt, bad_IRQ3_interrupt,
                    166:        bad_IRQ4_interrupt, bad_IRQ5_interrupt,
                    167:        bad_IRQ6_interrupt, bad_IRQ7_interrupt,
                    168:        bad_IRQ8_interrupt, bad_IRQ9_interrupt,
                    169:        bad_IRQ10_interrupt, bad_IRQ11_interrupt,
                    170:        bad_IRQ12_interrupt, bad_IRQ13_interrupt,
                    171:        bad_IRQ14_interrupt, bad_IRQ15_interrupt
                    172: };
                    173: 
                    174: /*
                    175:  * Initial irq handlers.
                    176:  */
                    177: 
                    178: static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
                    179: 
                    180: #ifdef __SMP__
                    181: 
                    182: /*
                    183:  * On SMP boards, irq13 is used for interprocessor interrupts (IPI's).
                    184:  */
                    185: static struct irqaction irq13 = { smp_message_irq, SA_INTERRUPT, 0, "IPI", NULL, NULL };
                    186: 
                    187: #else
                    188: 
                    189: /*
                    190:  * Note that on a 486, we don't want to do a SIGFPE on a irq13
                    191:  * as the irq is unreliable, and exception 16 works correctly
                    192:  * (ie as explained in the intel literature). On a 386, you
                    193:  * can't use exception 16 due to bad IBM design, so we have to
                    194:  * rely on the less exact irq13.
                    195:  *
                    196:  * Careful.. Not only is IRQ13 unreliable, but it is also
                    197:  * leads to races. IBM designers who came up with it should
                    198:  * be shot.
                    199:  */
                    200:  
                    201: 
                    202: static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
                    203: {
                    204:        outb(0,0xF0);
                    205:        if (ignore_irq13 || !hard_math)
                    206:                return;
                    207:        math_error();
                    208: }
                    209: 
                    210: static struct irqaction irq13 = { math_error_irq, 0, 0, "math error", NULL, NULL };
                    211: 
                    212: #endif
                    213: 
                    214: /*
                    215:  * IRQ2 is cascade interrupt to second interrupt controller
                    216:  */
                    217: static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL};
                    218: 
                    219: static struct irqaction *irq_action[16] = {
                    220:        NULL, NULL, NULL, NULL,
                    221:        NULL, NULL, NULL, NULL,
                    222:        NULL, NULL, NULL, NULL,
                    223:        NULL, NULL, NULL, NULL
                    224: };
                    225: 
                    226: int get_irq_list(char *buf)
                    227: {
                    228:        int i, len = 0;
                    229:        struct irqaction * action;
                    230: 
                    231:        for (i = 0 ; i < 16 ; i++) {
                    232:                action = irq_action[i];
                    233:                if (!action) 
                    234:                        continue;
                    235:                len += sprintf(buf+len, "%2d: %10u %c %s",
                    236:                        i, kstat.interrupts[i],
                    237:                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
                    238:                        action->name);
                    239:                for (action=action->next; action; action = action->next) {
                    240:                        len += sprintf(buf+len, ",%s %s",
                    241:                                (action->flags & SA_INTERRUPT) ? " +" : "",
                    242:                                action->name);
                    243:                }
                    244:                len += sprintf(buf+len, "\n");
                    245:        }
                    246: /*
                    247:  *     Linus - should you add NMI counts here ?????
                    248:  */
                    249: #ifdef __SMP_PROF__
                    250:        len+=sprintf(buf+len, "IPI: %8lu received\n",
                    251:                ipi_count);
                    252: #endif         
                    253:        return len;
                    254: }
                    255: 
                    256: #ifdef __SMP_PROF__
                    257: 
                    258: int get_smp_prof_list(char *buf) {
                    259:        int i,j, len = 0;
                    260:        struct irqaction * action;
                    261:        unsigned long sum_spins = 0;
                    262:        unsigned long sum_spins_syscall = 0;
                    263:        unsigned long sum_spins_sys_idle = 0;
                    264:        unsigned long sum_smp_idle_count = 0;
                    265: 
                    266:        for (i=0;i<smp_num_cpus;i++) {
                    267:                int cpunum = cpu_logical_map[i];
                    268:                sum_spins+=smp_spins[cpunum];
                    269:                sum_spins_syscall+=smp_spins_syscall[cpunum];
                    270:                sum_spins_sys_idle+=smp_spins_sys_idle[cpunum];
                    271:                sum_smp_idle_count+=smp_idle_count[cpunum];
                    272:        }
                    273: 
                    274:        len += sprintf(buf+len,"CPUS: %10i \n", smp_num_cpus);
                    275:        len += sprintf(buf+len,"            SUM ");
                    276:        for (i=0;i<smp_num_cpus;i++)
                    277:                len += sprintf(buf+len,"        P%1d ",cpu_logical_map[i]);
                    278:        len += sprintf(buf+len,"\n");
                    279:        for (i = 0 ; i < NR_IRQS ; i++) {
                    280:                action = *(i + irq_action);
                    281:                if (!action || !action->handler)
                    282:                        continue;
                    283:                len += sprintf(buf+len, "%3d: %10d ",
                    284:                        i, kstat.interrupts[i]);
                    285:                for (j=0;j<smp_num_cpus;j++)
                    286:                        len+=sprintf(buf+len, "%10d ",
                    287:                                int_count[cpu_logical_map[j]][i]);
                    288:                len += sprintf(buf+len, "%c %s",
                    289:                        (action->flags & SA_INTERRUPT) ? '+' : ' ',
                    290:                        action->name);
                    291:                for (action=action->next; action; action = action->next) {
                    292:                        len += sprintf(buf+len, ",%s %s",
                    293:                                (action->flags & SA_INTERRUPT) ? " +" : "",
                    294:                                action->name);
                    295:                }
                    296:                len += sprintf(buf+len, "\n");
                    297:        }
                    298:        len+=sprintf(buf+len, "LCK: %10lu",
                    299:                sum_spins);
                    300: 
                    301:        for (i=0;i<smp_num_cpus;i++)
                    302:                len+=sprintf(buf+len," %10lu",smp_spins[cpu_logical_map[i]]);
                    303: 
                    304:        len +=sprintf(buf+len,"   spins from int\n");
                    305: 
                    306:        len+=sprintf(buf+len, "LCK: %10lu",
                    307:                sum_spins_syscall);
                    308: 
                    309:        for (i=0;i<smp_num_cpus;i++)
                    310:                len+=sprintf(buf+len," %10lu",smp_spins_syscall[cpu_logical_map[i]]);
                    311: 
                    312:        len +=sprintf(buf+len,"   spins from syscall\n");
                    313: 
                    314:        len+=sprintf(buf+len, "LCK: %10lu",
                    315:                sum_spins_sys_idle);
                    316: 
                    317:        for (i=0;i<smp_num_cpus;i++)
                    318:                len+=sprintf(buf+len," %10lu",smp_spins_sys_idle[cpu_logical_map[i]]);
                    319: 
                    320:        len +=sprintf(buf+len,"   spins from sysidle\n");
                    321:        len+=sprintf(buf+len,"IDLE %10lu",sum_smp_idle_count);
                    322: 
                    323:        for (i=0;i<smp_num_cpus;i++)
                    324:                len+=sprintf(buf+len," %10lu",smp_idle_count[cpu_logical_map[i]]);
                    325: 
                    326:        len +=sprintf(buf+len,"   idle ticks\n");
                    327: 
                    328:        len+=sprintf(buf+len, "IPI: %10lu   received\n",
                    329:                ipi_count);
                    330: 
                    331:        return len;
                    332: }
                    333: #endif 
                    334: 
                    335: 
                    336: 
                    337: /*
                    338:  * do_IRQ handles IRQ's that have been installed without the
                    339:  * SA_INTERRUPT flag: it uses the full signal-handling return
                    340:  * and runs with other interrupts enabled. All relatively slow
                    341:  * IRQ's should use this format: notably the keyboard/timer
                    342:  * routines.
                    343:  */
                    344: asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
                    345: {
                    346:        struct irqaction * action = *(irq + irq_action);
                    347:        int do_random = 0;
                    348:        int c,intm,mask;
                    349: #ifdef IRQ_DEBUG
                    350:        static int count;
                    351:        if (smp_processor_id() != 0 && count++ < 1000)
                    352:          printk("IRQ %d: done by CPU %d\n",irq,smp_processor_id());
                    353: #endif   
                    354:        if (irq  >= 8) {
                    355:          c = cache_A1;
                    356:          intm = inb(0xA1);
                    357:          mask =  1 << (irq - 8);
                    358:        } else {
                    359:          c = cache_21;
                    360:          intm = inb(0x21);
                    361:          mask =  1 << irq;
                    362:        }
                    363:        if (!(c & mask) || !(intm & mask)) {
                    364: #ifdef IRQ_DEBUG       
                    365:          printk("IRQ %d (proc %d):cache_x1=0x%x,INT mask=0x%x\n", irq, smp_processor_id(),c,intm);
                    366: #endif   
                    367:          /* better to return because the interrupt may be asserted again,
                    368:             the bad thing is that we may loose some interrupts */
                    369:          return;
                    370:        }
                    371: #ifdef __SMP__
                    372:        if(smp_threads_ready && active_kernel_processor!=smp_processor_id())
                    373:                panic("IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
                    374: #endif
                    375: 
                    376:        kstat.interrupts[irq]++;
                    377: #ifdef __SMP_PROF__
                    378:        int_count[smp_processor_id()][irq]++;
                    379: #endif
                    380:        while (action) {
                    381:                do_random |= action->flags;
                    382:                action->handler(irq, action->dev_id, regs);
                    383:                action = action->next;
                    384:        }
                    385:        if (do_random & SA_SAMPLE_RANDOM)
                    386:                add_interrupt_randomness(irq);
                    387: }
                    388: 
                    389: /*
                    390:  * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return
                    391:  * stuff - the handler is also running with interrupts disabled unless
                    392:  * it explicitly enables them later.
                    393:  */
                    394: asmlinkage void do_fast_IRQ(int irq)
                    395: {
                    396:        struct irqaction * action = *(irq + irq_action);
                    397:        int do_random = 0;
                    398:        
                    399: #ifdef __SMP__
                    400:        /* IRQ 13 is allowed - that's a flush tlb */
                    401:        if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
                    402:                panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
                    403: #endif
                    404: 
                    405:        kstat.interrupts[irq]++;
                    406: #ifdef __SMP_PROF__
                    407:        int_count[smp_processor_id()][irq]++;
                    408: #endif
                    409:        while (action) {
                    410:                do_random |= action->flags;
                    411:                action->handler(irq, action->dev_id, NULL);
                    412:                action = action->next;
                    413:        }
                    414:        if (do_random & SA_SAMPLE_RANDOM)
                    415:                add_interrupt_randomness(irq);
                    416: }
                    417: 
                    418: int setup_x86_irq(int irq, struct irqaction * new)
                    419: {
                    420:        int shared = 0;
                    421:        struct irqaction *old, **p;
                    422:        unsigned long flags;
                    423: 
                    424:        p = irq_action + irq;
                    425:        if ((old = *p) != NULL) {
                    426:                /* Can't share interrupts unless both agree to */
                    427:                if (!(old->flags & new->flags & SA_SHIRQ))
                    428:                        return -EBUSY;
                    429: 
                    430:                /* Can't share interrupts unless both are same type */
                    431:                if ((old->flags ^ new->flags) & SA_INTERRUPT)
                    432:                        return -EBUSY;
                    433: 
                    434:                /* add new interrupt at end of irq queue */
                    435:                do {
                    436:                        p = &old->next;
                    437:                        old = *p;
                    438:                } while (old);
                    439:                shared = 1;
                    440:        }
                    441: 
                    442:        if (new->flags & SA_SAMPLE_RANDOM)
                    443:                rand_initialize_irq(irq);
                    444: 
                    445:        save_flags(flags);
                    446:        cli();
                    447:        *p = new;
                    448: 
                    449:        if (!shared) {
                    450:                if (new->flags & SA_INTERRUPT)
                    451:                        set_intr_gate(0x20+irq,fast_interrupt[irq]);
                    452:                else
                    453:                        set_intr_gate(0x20+irq,interrupt[irq]);
                    454:                unmask_irq(irq);
                    455:        }
                    456:        restore_flags(flags);
                    457:        return 0;
                    458: }
                    459: 
                    460: int request_irq(unsigned int irq, 
                    461:                void (*handler)(int, void *, struct pt_regs *),
                    462:                unsigned long irqflags, 
                    463:                const char * devname,
                    464:                void *dev_id)
                    465: {
                    466:        int retval;
                    467:        struct irqaction * action;
                    468: 
                    469:        if (irq > 15)
                    470:                return -EINVAL;
                    471:        if (!handler)
                    472:                return -EINVAL;
                    473: 
                    474:        action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
                    475:        if (!action)
                    476:                return -ENOMEM;
                    477: 
                    478:        action->handler = handler;
                    479:        action->flags = irqflags;
                    480:        action->mask = 0;
                    481:        action->name = devname;
                    482:        action->next = NULL;
                    483:        action->dev_id = dev_id;
                    484: 
                    485:        retval = setup_x86_irq(irq, action);
                    486: 
                    487:        if (retval)
                    488:                kfree(action);
                    489:        return retval;
                    490: }
                    491:                
                    492: void free_irq(unsigned int irq, void *dev_id)
                    493: {
                    494:        struct irqaction * action, **p;
                    495:        unsigned long flags;
                    496: 
                    497:        if (irq > 15) {
                    498:                printk("Trying to free IRQ%d\n",irq);
                    499:                return;
                    500:        }
                    501:        for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
                    502:                if (action->dev_id != dev_id)
                    503:                        continue;
                    504: 
                    505:                /* Found it - now free it */
                    506:                save_flags(flags);
                    507:                cli();
                    508:                *p = action->next;
                    509:                if (!irq[irq_action]) {
                    510:                        mask_irq(irq);
                    511:                        set_intr_gate(0x20+irq,bad_interrupt[irq]);
                    512:                }
                    513:                restore_flags(flags);
                    514:                kfree(action);
                    515:                return;
                    516:        }
                    517:        printk("Trying to free free IRQ%d\n",irq);
                    518: }
                    519: 
                    520: unsigned long probe_irq_on (void)
                    521: {
                    522:        unsigned int i, irqs = 0, irqmask;
                    523:        unsigned long delay;
                    524: 
                    525:        /* first, enable any unassigned irqs */
                    526:        for (i = 15; i > 0; i--) {
                    527:                if (!irq_action[i]) {
                    528:                        enable_irq(i);
                    529:                        irqs |= (1 << i);
                    530:                }
                    531:        }
                    532: 
                    533:        /* wait for spurious interrupts to mask themselves out again */
                    534:        for (delay = jiffies + HZ/10; delay > jiffies; )
                    535:                /* about 100ms delay */;
                    536: 
                    537:        /* now filter out any obviously spurious interrupts */
                    538:        irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
                    539:        return irqs & ~irqmask;
                    540: }
                    541: 
                    542: int probe_irq_off (unsigned long irqs)
                    543: {
                    544:        unsigned int i, irqmask;
                    545: 
                    546:        irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
                    547: #ifdef DEBUG
                    548:        printk("probe_irq_off: irqs=0x%04lx irqmask=0x%04x\n", irqs, irqmask);
                    549: #endif
                    550:        irqs &= irqmask;
                    551:        if (!irqs)
                    552:                return 0;
                    553:        i = ffz(~irqs);
                    554:        if (irqs != (irqs & (1 << i)))
                    555:                i = -i;
                    556:        return i;
                    557: }
                    558: 
                    559: void init_IRQ(void)
                    560: {
                    561:        int i;
                    562:        static unsigned char smptrap=0;
                    563:        if(smptrap)
                    564:                return;
                    565:        smptrap=1;
                    566: 
                    567:        /* set the clock to 100 Hz */
                    568:        outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
                    569:        outb_p(LATCH & 0xff , 0x40);    /* LSB */
                    570:        outb(LATCH >> 8 , 0x40);        /* MSB */
                    571:        for (i = 0; i < 16 ; i++)
                    572:                set_intr_gate(0x20+i,bad_interrupt[i]);
                    573:        /* This bit is a hack because we don't send timer messages to all processors yet */
                    574:        /* It has to be here .. it doesn't work if you put it down the bottom - assembler explodes 8) */
                    575: #ifdef __SMP__ 
                    576:        set_intr_gate(0x20+i, interrupt[i]);    /* IRQ '16' - IPI for rescheduling */
                    577: #endif 
                    578:        request_region(0x20,0x20,"pic1");
                    579:        request_region(0xa0,0x20,"pic2");
                    580:        setup_x86_irq(2, &irq2);
                    581:        setup_x86_irq(13, &irq13);
                    582: } 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.