ints.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/m68k/hp300/ints.c
  3.  *
  4.  *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
  5.  *
  6.  *  This file contains the HP300-specific interrupt handling.
  7.  *  We only use the autovector interrupts, and therefore we need to
  8.  *  maintain lists of devices sharing each ipl.
  9.  *  [ipl list code added by Peter Maydell <pmaydell@chiark.greenend.org.uk> 06/1998]
  10.  */
  11. #include <linux/kernel.h>
  12. #include <linux/types.h>
  13. #include <linux/init.h>
  14. #include <linux/sched.h>
  15. #include <linux/kernel_stat.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/spinlock.h>
  18. #include <asm/machdep.h>
  19. #include <asm/irq.h>
  20. #include <asm/io.h>
  21. #include <asm/system.h>
  22. #include <asm/traps.h>
  23. #include <asm/ptrace.h>
  24. #include "ints.h"
  25. /* Each ipl has a linked list of interrupt service routines.
  26.  * Service routines are added via hp300_request_irq() and removed
  27.  * via hp300_free_irq(). The device driver should set IRQ_FLG_FAST
  28.  * if it needs to be serviced early (eg FIFOless UARTs); this will
  29.  * cause it to be added at the front of the queue rather than 
  30.  * the back.
  31.  * Currently IRQ_FLG_SLOW and flags=0 are treated identically; if
  32.  * we needed three levels of priority we could distinguish them
  33.  * but this strikes me as mildly ugly...
  34.  */
  35. /* we start with no entries in any list */
  36. static irq_node_t *hp300_irq_list[HP300_NUM_IRQS] = { [0 ... HP300_NUM_IRQS-1] = NULL };
  37. static spinlock_t irqlist_lock;
  38. /* This handler receives all interrupts, dispatching them to the registered handlers */
  39. static void hp300_int_handler(int irq, void *dev_id, struct pt_regs *fp)
  40. {
  41.         irq_node_t *t;
  42.         /* We just give every handler on the chain an opportunity to handle
  43.          * the interrupt, in priority order.
  44.          */
  45.         for(t = hp300_irq_list[irq]; t; t=t->next)
  46.                 t->handler(irq, t->dev_id, fp);
  47.         /* We could put in some accounting routines, checks for stray interrupts,
  48.          * etc, in here. Note that currently we can't tell whether or not
  49.          * a handler handles the interrupt, though. 
  50.          */
  51. }
  52. void (*hp300_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
  53. hp300_int_handler, hp300_int_handler, hp300_int_handler, hp300_int_handler,
  54. hp300_int_handler, hp300_int_handler, hp300_int_handler, NULL
  55. };
  56. /* dev_id had better be unique to each handler because it's the only way we have
  57.  * to distinguish handlers when removing them...
  58.  *
  59.  * It would be pretty easy to support IRQ_FLG_LOCK (handler is not replacable)
  60.  * and IRQ_FLG_REPLACE (handler replaces existing one with this dev_id)
  61.  * if we wanted to. IRQ_FLG_FAST is needed for devices where interrupt latency
  62.  * matters (eg the dreaded FIFOless UART...)
  63.  */
  64. int hp300_request_irq(unsigned int irq,
  65.                       void (*handler) (int, void *, struct pt_regs *),
  66.                       unsigned long flags, const char *devname, void *dev_id)
  67. {
  68.         irq_node_t *t, *n = new_irq_node();
  69.         
  70.         if (!n)                                   /* oops, no free nodes */
  71.                 return -ENOMEM;
  72. spin_lock_irqsave(&irqlist_lock, flags);
  73.         if (!hp300_irq_list[irq]) {
  74.                 /* no list yet */
  75.                 hp300_irq_list[irq] = n;
  76.                 n->next = NULL;
  77.         } else if (flags & IRQ_FLG_FAST) {
  78.                 /* insert at head of list */
  79.                 n->next = hp300_irq_list[irq];
  80.                 hp300_irq_list[irq] = n;
  81.         } else {
  82.                 /* insert at end of list */
  83.                 for(t = hp300_irq_list[irq]; t->next; t = t->next)
  84.                         /* do nothing */;
  85.                 n->next = NULL;
  86.                 t->next = n;
  87.         }
  88.         /* Fill in n appropriately */
  89.         n->handler = handler;
  90.         n->flags = flags;
  91.         n->dev_id = dev_id;
  92.         n->devname = devname;
  93. spin_unlock_irqrestore(&irqlist_lock, flags);
  94. return 0;
  95. }
  96. void hp300_free_irq(unsigned int irq, void *dev_id)
  97. {
  98.         irq_node_t *t;
  99.         unsigned long flags;
  100.         spin_lock_irqsave(&irqlist_lock, flags);
  101.         
  102.         t = hp300_irq_list[irq];
  103.         if (!t)                                   /* no handlers at all for that IRQ */
  104.         {
  105.                 printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %dn", irq);
  106.                 spin_unlock_irqrestore(&irqlist_lock, flags);
  107. return;
  108.         }
  109.         
  110.         if (t->dev_id == dev_id)
  111.         {                                         /* removing first handler on chain */
  112.                 t->flags = IRQ_FLG_STD;           /* we probably don't really need these */
  113.                 t->dev_id = NULL;
  114.                 t->devname = NULL;
  115.                 t->handler = NULL;                /* frees this irq_node_t */
  116.                 hp300_irq_list[irq] = t->next;
  117. spin_unlock_irqrestore(&irqlist_lock, flags);
  118. return;
  119.         }
  120.         
  121.         /* OK, must be removing from middle of the chain */
  122.         
  123.         for (t = hp300_irq_list[irq]; t->next && t->next->dev_id != dev_id; t = t->next)
  124.                 /* do nothing */;
  125.         if (!t->next)
  126.         {
  127.                 printk(KERN_ERR "hp300_free_irq: attempt to remove nonexistent handler for IRQ %dn", irq);
  128. spin_unlock_irqrestore(&irqlist_lock, flags);
  129. return;
  130.         }
  131.         /* remove the entry after t: */
  132.         t->next->flags = IRQ_FLG_STD;
  133.         t->next->dev_id = t->next->devname = t->next->handler = NULL;
  134.         t->next = t->next->next;
  135.         
  136. spin_unlock_irqrestore(&irqlist_lock, flags);
  137. }
  138. int hp300_get_irq_list(char *buf)
  139. {
  140. return 0;
  141. }
  142. void __init hp300_init_IRQ(void)
  143. {
  144. spin_lock_init(&irqlist_lock);
  145. }