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

1.1       root        1: /*
                      2:  * Linux IRQ management.
                      3:  * Copyright (C) 1995 Shantanu Goel.
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify
                      6:  * it under the terms of the GNU General Public License as published by
                      7:  * the Free Software Foundation; either version 2, or (at your option)
                      8:  * any later version.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful,
                     11:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     12:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     13:  * GNU General Public License for more details.
                     14:  *
                     15:  * You should have received a copy of the GNU General Public License
                     16:  * along with this program; if not, write to the Free Software
                     17:  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
                     18:  */
                     19: 
                     20: /*
                     21:  *    linux/arch/i386/kernel/irq.c
                     22:  *
                     23:  *      Copyright (C) 1992 Linus Torvalds
                     24:  */
                     25: 
                     26: #include <sys/types.h>
                     27: #include <mach/mach_types.h>
                     28: #include <mach/vm_param.h>
                     29: #include <kern/assert.h>
                     30: 
                     31: #include <i386/spl.h>
                     32: #include <i386/pic.h>
                     33: #include <i386/pit.h>
                     34: 
                     35: #define MACH_INCLUDE
                     36: #include <linux/mm.h>
                     37: #include <linux/interrupt.h>
                     38: #include <linux/ptrace.h>
                     39: #include <linux/delay.h>
                     40: #include <linux/kernel_stat.h>
                     41: #include <linux/malloc.h>
                     42: #include <linux/ioport.h>
                     43: 
                     44: #include <asm/system.h>
                     45: #include <asm/bitops.h>
                     46: #include <asm/irq.h>
                     47: #include <asm/io.h>
                     48: 
                     49: extern int linux_timer_intr (void);
                     50: extern spl_t splhigh (void);
                     51: extern spl_t spl0 (void);
                     52: extern void form_pic_mask (void);
                     53: 
                     54: /*
                     55:  * XXX Move this into more suitable place...
                     56:  * Set if the machine has an EISA bus.
                     57:  */
                     58: int EISA_bus = 0;
                     59: 
                     60: /*
                     61:  * Priority at which a Linux handler should be called.
                     62:  * This is used at the time of an IRQ allocation.  It is
                     63:  * set by emulation routines for each class of device.
                     64:  */
                     65: spl_t linux_intr_pri;
                     66: 
                     67: /*
                     68:  * Flag indicating an interrupt is being handled.
                     69:  */
                     70: unsigned long intr_count = 0;
                     71: 
                     72: /*
                     73:  * List of Linux interrupt handlers.
                     74:  */
                     75: struct linux_action
                     76: {
                     77:   void (*handler) (int, void *, struct pt_regs *);
                     78:   void *dev_id;
                     79:   struct linux_action *next;
                     80:   unsigned long flags;
                     81: };
                     82: 
                     83: static struct linux_action *irq_action[16] =
                     84: {
                     85:   NULL, NULL, NULL, NULL,
                     86:   NULL, NULL, NULL, NULL,
                     87:   NULL, NULL, NULL, NULL,
                     88:   NULL, NULL, NULL, NULL
                     89: };
                     90: 
                     91: extern spl_t curr_ipl;
                     92: extern int curr_pic_mask;
                     93: extern int pic_mask[];
                     94: 
                     95: extern int intnull (), prtnull ();
                     96: 
                     97: /*
                     98:  * Generic interrupt handler for Linux devices.
                     99:  * Set up a fake `struct pt_regs' then call the real handler.
                    100:  */
                    101: static int
                    102: linux_intr (int irq)
                    103: {
                    104:   struct pt_regs regs;
                    105:   struct linux_action *action = *(irq_action + irq);
                    106: 
                    107:   kstat.interrupts[irq]++;
                    108:   intr_count++;
                    109: 
                    110:   while (action)
                    111:     {
                    112:       action->handler (irq, action->dev_id, &regs);
                    113:       action = action->next;
                    114:     }
                    115: 
                    116:   intr_count--;
                    117: 
                    118:   /* Not used. by OKUJI Yoshinori. */
                    119:   return 0;
                    120: }
                    121: 
                    122: /*
                    123:  * Mask an IRQ.
                    124:  */
                    125: static inline void
                    126: mask_irq (unsigned int irq_nr)
                    127: {
                    128:   int i;
                    129: 
                    130:   for (i = 0; i < intpri[irq_nr]; i++)
                    131:     pic_mask[i] |= 1 << irq_nr;
                    132: 
                    133:   if (curr_pic_mask != pic_mask[curr_ipl])
                    134:     {
                    135:       curr_pic_mask = pic_mask[curr_ipl];
                    136:       if (irq_nr < 8)
                    137:        outb (curr_pic_mask & 0xff, PIC_MASTER_OCW);
                    138:       else
                    139:        outb (curr_pic_mask >> 8, PIC_SLAVE_OCW);
                    140:     }
                    141: }
                    142: 
                    143: /*
                    144:  * Unmask an IRQ.
                    145:  */
                    146: static inline void
                    147: unmask_irq (unsigned int irq_nr)
                    148: {
                    149:   int mask, i;
                    150: 
                    151:   mask = 1 << irq_nr;
                    152:   if (irq_nr >= 8)
                    153:     mask |= 1 << 2;
                    154: 
                    155:   for (i = 0; i < intpri[irq_nr]; i++)
                    156:     pic_mask[i] &= ~mask;
                    157: 
                    158:   if (curr_pic_mask != pic_mask[curr_ipl])
                    159:     {
                    160:       curr_pic_mask = pic_mask[curr_ipl];
                    161:       if (irq_nr < 8)
                    162:        outb (curr_pic_mask & 0xff, PIC_MASTER_OCW);
                    163:       else
                    164:        outb (curr_pic_mask >> 8, PIC_SLAVE_OCW);
                    165:     }
                    166: }
                    167: 
                    168: void
                    169: disable_irq (unsigned int irq_nr)
                    170: {
                    171:   unsigned long flags;
                    172: 
                    173:   assert (irq_nr < NR_IRQS);
                    174: 
                    175:   save_flags (flags);
                    176:   cli ();
                    177:   mask_irq (irq_nr);
                    178:   restore_flags (flags);
                    179: }
                    180: 
                    181: void
                    182: enable_irq (unsigned int irq_nr)
                    183: {
                    184:   unsigned long flags;
                    185: 
                    186:   assert (irq_nr < NR_IRQS);
                    187: 
                    188:   save_flags (flags);
                    189:   cli ();
                    190:   unmask_irq (irq_nr);
                    191:   restore_flags (flags);
                    192: }
                    193: 
                    194: /*
                    195:  * Default interrupt handler for Linux.
                    196:  */
                    197: int
                    198: linux_bad_intr (int irq)
                    199: {
                    200:   mask_irq (irq);
                    201:   return 0;
                    202: }
                    203: 
                    204: static int
                    205: setup_x86_irq (int irq, struct linux_action *new)
                    206: {
                    207:   int shared = 0;
                    208:   struct linux_action *old, **p;
                    209:   unsigned long flags;
                    210: 
                    211:   p = irq_action + irq;
                    212:   if ((old = *p) != NULL)
                    213:     {
                    214:       /* Can't share interrupts unless both agree to */
                    215:       if (!(old->flags & new->flags & SA_SHIRQ))
                    216:        return (-LINUX_EBUSY);
                    217: 
                    218:       /* Can't share interrupts unless both are same type */
                    219:       if ((old->flags ^ new->flags) & SA_INTERRUPT)
                    220:        return (-LINUX_EBUSY);
                    221: 
                    222:       /* add new interrupt at end of irq queue */
                    223:       do
                    224:        {
                    225:          p = &old->next;
                    226:          old = *p;
                    227:        }
                    228:       while (old);
                    229:       shared = 1;
                    230:     }
                    231: 
                    232:   save_flags (flags);
                    233:   cli ();
                    234:   *p = new;
                    235: 
                    236:   if (!shared)
                    237:     {
                    238:       ivect[irq] = linux_intr;
                    239:       iunit[irq] = irq;
                    240:       intpri[irq] = linux_intr_pri;
                    241:       unmask_irq (irq);
                    242:     }
                    243:   restore_flags (flags);
                    244:   return 0;
                    245: }
                    246: 
                    247: /*
                    248:  * Attach a handler to an IRQ.
                    249:  */
                    250: int
                    251: request_irq (unsigned int irq, void (*handler) (int, void *, struct pt_regs *),
                    252:             unsigned long flags, const char *device, void *dev_id)
                    253: {
                    254:   struct linux_action *action;
                    255:   int retval;
                    256: 
                    257:   assert (irq < 16);
                    258: 
                    259:   if (!handler)
                    260:     return -LINUX_EINVAL;
                    261:   
                    262:   /*
                    263:    * Hmm... Should I use `kalloc()' ?
                    264:    * By OKUJI Yoshinori.
                    265:    */
                    266:   action = (struct linux_action *)
                    267:     linux_kmalloc (sizeof (struct linux_action), GFP_KERNEL);
                    268:   if (action == NULL)
                    269:     return -LINUX_ENOMEM;
                    270:   
                    271:   action->handler = handler;
                    272:   action->next = NULL;
                    273:   action->dev_id = dev_id;
                    274:   action->flags = flags;
                    275:   
                    276:   retval = setup_x86_irq (irq, action);
                    277:   if (retval)
                    278:     linux_kfree (action);
                    279:   
                    280:   return retval;
                    281: }
                    282: 
                    283: /*
                    284:  * Deallocate an irq.
                    285:  */
                    286: void
                    287: free_irq (unsigned int irq, void *dev_id)
                    288: {
                    289:   struct linux_action *action, **p;
                    290:   unsigned long flags;
                    291: 
                    292:   if (irq > 15)
                    293:     panic ("free_irq: bad irq number");
                    294: 
                    295:   for (p = irq_action + irq; (action = *p) != NULL; p = &action->next)
                    296:     {
                    297:       if (action->dev_id != dev_id)
                    298:        continue;
                    299: 
                    300:       save_flags (flags);
                    301:       cli ();
                    302:       *p = action->next;
                    303:       if (!irq_action[irq])
                    304:        {
                    305:          mask_irq (irq);
                    306:          ivect[irq] = linux_bad_intr;
                    307:          iunit[irq] = irq;
                    308:          intpri[irq] = SPL0;
                    309:        }
                    310:       restore_flags (flags);
                    311:       linux_kfree (action);
                    312:       return;
                    313:     }
                    314: 
                    315:   panic ("free_irq: bad irq number");
                    316: }
                    317: 
                    318: /*
                    319:  * Set for an irq probe.
                    320:  */
                    321: unsigned long
                    322: probe_irq_on (void)
                    323: {
                    324:   unsigned i, irqs = 0;
                    325:   unsigned long delay;
                    326: 
                    327:   assert (curr_ipl == 0);
                    328: 
                    329:   /*
                    330:    * Allocate all available IRQs.
                    331:    */
                    332:   for (i = 15; i > 0; i--)
                    333:     {
                    334:       if (!irq_action[i] && ivect[i] == linux_bad_intr)
                    335:        {
                    336:          intpri[i] = linux_intr_pri;
                    337:          enable_irq (i);
                    338:          irqs |= 1 << i;
                    339:        }
                    340:     }
                    341: 
                    342:   /*
                    343:    * Wait for spurious interrupts to mask themselves out.
                    344:    */
                    345:   for (delay = jiffies + HZ / 10; delay > jiffies;)
                    346:     ;
                    347: 
                    348:   return (irqs & ~curr_pic_mask);
                    349: }
                    350: 
                    351: /*
                    352:  * Return the result of an irq probe.
                    353:  */
                    354: int
                    355: probe_irq_off (unsigned long irqs)
                    356: {
                    357:   unsigned int i;
                    358: 
                    359:   assert (curr_ipl == 0);
                    360: 
                    361:   irqs &= curr_pic_mask;
                    362: 
                    363:   /*
                    364:    * Disable unnecessary IRQs.
                    365:    */
                    366:   for (i = 15; i > 0; i--)
                    367:     {
                    368:       if (!irq_action[i] && ivect[i] == linux_bad_intr)
                    369:        {
                    370:          disable_irq (i);
                    371:          intpri[i] = SPL0;
                    372:        }
                    373:     }
                    374:   
                    375:   /*
                    376:    * Return IRQ number.
                    377:    */
                    378:   if (!irqs)
                    379:     return 0;
                    380:   i = ffz (~irqs);
                    381:   if (irqs != (irqs & (1 << i)))
                    382:     i = -i;
                    383:   return i;
                    384: }
                    385: 
                    386: /*
                    387:  * Reserve IRQs used by Mach drivers.
                    388:  * Must be called before Linux IRQ detection, after Mach IRQ detection.
                    389:  */
                    390: static void
                    391: reserve_mach_irqs (void)
                    392: {
                    393:   unsigned int i;
                    394: 
                    395:   for (i = 0; i < 16; i++)
                    396:     {
                    397:       if (ivect[i] != prtnull && ivect[i] != intnull)
                    398:        /* Set non-NULL value. */
                    399:        irq_action[i] = (struct linux_action *) -1;
                    400:     }
                    401: }
                    402: 
                    403: static int (*old_clock_handler) ();
                    404: static int old_clock_pri;
                    405: 
                    406: void
                    407: init_IRQ (void)
                    408: {
                    409:   int i;
                    410:   char *p;
                    411:   int latch = (CLKNUM + hz / 2) / hz;
                    412:   
                    413:   /*
                    414:    * Ensure interrupts are disabled.
                    415:    */
                    416:   (void) splhigh ();
                    417:   
                    418:   /*
                    419:    * Program counter 0 of 8253 to interrupt hz times per second.
                    420:    */
                    421:   outb_p (PIT_C0 | PIT_SQUAREMODE | PIT_READMODE, PITCTL_PORT);
                    422:   outb_p (latch && 0xff, PITCTR0_PORT);
                    423:   outb (latch >> 8, PITCTR0_PORT);
                    424:   
                    425:   /*
                    426:    * Install our clock interrupt handler.
                    427:    */
                    428:   old_clock_handler = ivect[0];
                    429:   old_clock_pri = intpri[0];
                    430:   ivect[0] = linux_timer_intr;
                    431:   intpri[0] = SPLHI;
                    432: 
                    433:   reserve_mach_irqs ();
                    434: 
                    435:   for (i = 1; i < 16; i++)
                    436:     {
                    437:       /*
                    438:        * irq2 and irq13 should be igonored.
                    439:        */
                    440:       if (i == 2 || i == 13)
                    441:        continue;
                    442:       if (ivect[i] == prtnull || ivect[i] == intnull)
                    443:        {
                    444:           ivect[i] = linux_bad_intr;
                    445:           iunit[i] = i;
                    446:           intpri[i] = SPL0;
                    447:        }
                    448:     }
                    449:   
                    450:   form_pic_mask ();
                    451:   
                    452:   /*
                    453:    * Enable interrupts.
                    454:    */
                    455:   (void) spl0 ();
                    456:   
                    457:   /*
                    458:    * Check if the machine has an EISA bus.
                    459:    */
                    460:   p = (char *) 0x0FFFD9;
                    461:   if (*p++ == 'E' && *p++ == 'I' && *p++ == 'S' && *p == 'A')
                    462:     EISA_bus = 1;
                    463:   
                    464:   /*
                    465:    * Permanently allocate standard device ports.
                    466:    */
                    467:   request_region (0x00, 0x20, "dma1");
                    468:   request_region (0x20, 0x20, "pic1");
                    469:   request_region (0x40, 0x20, "timer");
                    470:   request_region (0x70, 0x10, "rtc");
                    471:   request_region (0x80, 0x20, "dma page reg");
                    472:   request_region (0xa0, 0x20, "pic2");
                    473:   request_region (0xc0, 0x20, "dma2");
                    474:   request_region (0xf0, 0x10, "npu");
                    475: }
                    476: 
                    477: void
                    478: restore_IRQ (void)
                    479: {
                    480:   /*
                    481:    * Disable interrupts.
                    482:    */
                    483:   (void) splhigh ();
                    484:   
                    485:   /*
                    486:    * Restore clock interrupt handler.
                    487:    */
                    488:   ivect[0] = old_clock_handler;
                    489:   intpri[0] = old_clock_pri;
                    490:   form_pic_mask ();
                    491: }
                    492:   

unix.superglobalmegacorp.com

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