Annotation of Gnu-Mach/linux/dev/arch/i386/kernel/irq.c, revision 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.