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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/mips/philips/nino/irq.c
  3.  *
  4.  *  Copyright (C) 1992 Linus Torvalds
  5.  *  Copyright (C) 1999 Harald Koerfgen
  6.  *  Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
  7.  *  Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com)
  8.  * 
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License version 2 as
  11.  * published by the Free Software Foundation.
  12.  *  
  13.  *  Generic interrupt handler for Philips Nino.
  14.  */
  15. #include <linux/errno.h>
  16. #include <linux/init.h>
  17. #include <linux/kernel_stat.h>
  18. #include <linux/signal.h>
  19. #include <linux/sched.h>
  20. #include <linux/types.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/ioport.h>
  23. #include <linux/timex.h>
  24. #include <linux/slab.h>
  25. #include <linux/random.h>
  26. #include <asm/bitops.h>
  27. #include <asm/bootinfo.h>
  28. #include <asm/io.h>
  29. #include <asm/irq.h>
  30. #include <asm/mipsregs.h>
  31. #include <asm/system.h>
  32. #include <asm/tx3912.h>
  33. unsigned long spurious_count = 0;
  34. irq_cpustat_t irq_stat [NR_CPUS];
  35. static inline void mask_irq(unsigned int irq_nr)
  36. {
  37. switch (irq_nr) {
  38. case 0:  /* Periodic Timer Interrupt */ 
  39. IntClear5 = INT5_PERIODICINT;
  40. IntClear6 = INT6_PERIODICINT;
  41. IntEnable6 &= ~INT6_PERIODICINT;
  42. break;
  43. case 3:
  44. /* Serial port receive interrupt */
  45. break;
  46. case 2:
  47. /* Serial port transmit interrupt */
  48. break;
  49. default:
  50. printk( "Attempt to mask unknown IRQ %d?n", irq_nr );
  51. }
  52. }
  53. static inline void unmask_irq(unsigned int irq_nr)
  54. {
  55. switch (irq_nr) {
  56. case 0:
  57. IntEnable6 |= INT6_PERIODICINT;
  58. break;
  59. case 3:
  60. /* Serial port receive interrupt */
  61. break;
  62. case 2:
  63. /* Serial port transmit interrupt */
  64. break;
  65. default:
  66. printk( "Attempt to unmask unknown IRQ %d?n", irq_nr );
  67. }
  68. }
  69. void disable_irq(unsigned int irq_nr)
  70. {
  71.     unsigned long flags;
  72.     save_and_cli(flags);
  73.     mask_irq(irq_nr);
  74.     restore_flags(flags);
  75. }
  76. void enable_irq(unsigned int irq_nr)
  77. {
  78.     unsigned long flags;
  79.     save_and_cli(flags);
  80.     unmask_irq(irq_nr);
  81.     restore_flags(flags);
  82. }
  83. /*
  84.  * Pointers to the low-level handlers: first the general ones, then the
  85.  * fast ones, then the bad ones.
  86.  */
  87. extern void interrupt(void);
  88. static struct irqaction *irq_action[NR_IRQS] =
  89. {
  90.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  91.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  92.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  93.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  94.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  95.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  96.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  97.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
  98. };
  99. int get_irq_list(char *buf)
  100. {
  101.     int i, len = 0;
  102.     struct irqaction *action;
  103.     for (i = 0; i < NR_IRQS; i++) {
  104. action = irq_action[i];
  105. if (!action)
  106.     continue;
  107. len += sprintf(buf + len, "%2d: %8d %c %s",
  108.        i, kstat.irqs[0][i],
  109.        (action->flags & SA_INTERRUPT) ? '+' : ' ',
  110.        action->name);
  111. for (action = action->next; action; action = action->next) {
  112.     len += sprintf(buf + len, ",%s %s",
  113.    (action->flags & SA_INTERRUPT) ? " +" : "",
  114.    action->name);
  115. }
  116. len += sprintf(buf + len, "n");
  117.     }
  118.     return len;
  119. }
  120. atomic_t __mips_bh_counter;
  121. /*
  122.  * do_IRQ handles IRQ's that have been installed without the
  123.  * SA_INTERRUPT flag: it uses the full signal-handling return
  124.  * and runs with other interrupts enabled. All relatively slow
  125.  * IRQ's should use this format: notably the keyboard/timer
  126.  * routines.
  127.  */
  128. asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
  129. {
  130.     struct irqaction *action;
  131.     int do_random, cpu;
  132.     if (irq == 20) {
  133.         if (IntStatus2 & 0xfffff00) {
  134. if (IntStatus2 & 0x0f000000)
  135. return do_IRQ(2, regs);
  136. }
  137.     }
  138.     cpu = smp_processor_id();
  139.     irq_enter(cpu, irq);
  140.     kstat.irqs[cpu][irq]++;
  141.     if (irq == 20) {
  142.             printk("20 %08lx %08lxn   %08lx %08lxn   %08lxn",
  143.                    IntStatus1, IntStatus2, IntStatus3,
  144.                    IntStatus4, IntStatus5 );
  145.             printk("20 %08lx %08lxn   %08lx %08lxn   %08lxn",
  146.                    IntEnable1, IntEnable2, IntEnable3,
  147.                    IntEnable4, IntEnable5 );
  148.     }
  149.     mask_irq(irq);
  150.     action = *(irq + irq_action);
  151.     if (action) {
  152. if (!(action->flags & SA_INTERRUPT))
  153.     __sti();
  154. do_random = 0;
  155. do {
  156.     do_random |= action->flags;
  157.     action->handler(irq, action->dev_id, regs);
  158.     action = action->next;
  159. } while (action);
  160. if (do_random & SA_SAMPLE_RANDOM)
  161.     add_interrupt_randomness(irq);
  162. unmask_irq(irq);
  163. __cli();
  164.     } else {
  165.             IntClear1 = ~0;
  166.             IntClear3 = ~0;
  167.     IntClear4 = ~0;
  168.     IntClear5 = ~0;
  169.     unmask_irq(irq);
  170.     }
  171.     irq_exit(cpu, irq);
  172.     /* unmasking and bottom half handling is done magically for us. */
  173. }
  174. /*
  175.  * Idea is to put all interrupts
  176.  * in a single table and differenciate them just by number.
  177.  */
  178. int setup_nino_irq(int irq, struct irqaction *new)
  179. {
  180.     int shared = 0;
  181.     struct irqaction *old, **p;
  182.     unsigned long flags;
  183.     p = irq_action + irq;
  184.     if ((old = *p) != NULL) {
  185. /* Can't share interrupts unless both agree to */
  186. if (!(old->flags & new->flags & SA_SHIRQ))
  187.     return -EBUSY;
  188. /* Can't share interrupts unless both are same type */
  189. if ((old->flags ^ new->flags) & SA_INTERRUPT)
  190.     return -EBUSY;
  191. /* add new interrupt at end of irq queue */
  192. do {
  193.     p = &old->next;
  194.     old = *p;
  195. } while (old);
  196. shared = 1;
  197.     }
  198.     if (new->flags & SA_SAMPLE_RANDOM)
  199. rand_initialize_irq(irq);
  200.     save_and_cli(flags);
  201.     *p = new;
  202.     if (!shared) {
  203. unmask_irq(irq);
  204.     }
  205.     restore_flags(flags);
  206.     return 0;
  207. }
  208. int request_irq(unsigned int irq,
  209. void (*handler) (int, void *, struct pt_regs *),
  210. unsigned long irqflags,
  211. const char *devname,
  212. void *dev_id)
  213. {
  214.     int retval;
  215.     struct irqaction *action;
  216.     if (irq >= NR_IRQS)
  217. return -EINVAL;
  218.     if (!handler)
  219. return -EINVAL;
  220.     action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL);
  221.     if (!action)
  222. return -ENOMEM;
  223.     action->handler = handler;
  224.     action->flags = irqflags;
  225.     action->mask = 0;
  226.     action->name = devname;
  227.     action->next = NULL;
  228.     action->dev_id = dev_id;
  229.     retval = setup_nino_irq(irq, action);
  230.     if (retval)
  231. kfree(action);
  232.     return retval;
  233. }
  234. void free_irq(unsigned int irq, void *dev_id)
  235. {
  236.     struct irqaction *action, **p;
  237.     unsigned long flags;
  238.     if (irq >= NR_IRQS) {
  239. printk(KERN_CRIT __FUNCTION__ ": trying to free IRQ%dn", irq);
  240. return;
  241.     }
  242.     for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
  243. if (action->dev_id != dev_id)
  244.     continue;
  245. /* Found it - now free it */
  246. save_and_cli(flags);
  247. *p = action->next;
  248. if (!irq[irq_action])
  249.     mask_irq(irq);
  250. restore_flags(flags);
  251. kfree(action);
  252. return;
  253.     }
  254.     printk(KERN_CRIT __FUNCTION__ ": trying to free free IRQ%dn", irq);
  255. }
  256. unsigned long probe_irq_on(void)
  257. {
  258.     /* TODO */
  259.     return 0;
  260. }
  261. int probe_irq_off(unsigned long irqs)
  262. {
  263.     /* TODO */
  264.     return 0;
  265. }
  266. void __init init_IRQ(void)
  267. {
  268.     irq_setup();
  269. }