home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / alpha / kernel / irq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-26  |  8.8 KB  |  415 lines

  1. /*
  2.  *    linux/arch/alpha/kernel/irq.c
  3.  *
  4.  *    Copyright (C) 1995 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. #include <linux/config.h>
  14. #include <linux/ptrace.h>
  15. #include <linux/errno.h>
  16. #include <linux/kernel_stat.h>
  17. #include <linux/signal.h>
  18. #include <linux/sched.h>
  19. #include <linux/interrupt.h>
  20.  
  21. #include <asm/system.h>
  22. #include <asm/io.h>
  23. #include <asm/irq.h>
  24. #include <asm/bitops.h>
  25. #include <asm/dma.h>
  26.  
  27. static unsigned char cache_21 = 0xff;
  28. static unsigned char cache_A1 = 0xff;
  29.  
  30. void disable_irq(unsigned int irq_nr)
  31. {
  32.     unsigned long flags;
  33.     unsigned char mask;
  34.  
  35.     mask = 1 << (irq_nr & 7);
  36.     save_flags(flags);
  37.     if (irq_nr < 8) {
  38.         cli();
  39.         cache_21 |= mask;
  40.         outb(cache_21,0x21);
  41.         restore_flags(flags);
  42.         return;
  43.     }
  44.     cli();
  45.     cache_A1 |= mask;
  46.     outb(cache_A1,0xA1);
  47.     restore_flags(flags);
  48. }
  49.  
  50. void enable_irq(unsigned int irq_nr)
  51. {
  52.     unsigned long flags;
  53.     unsigned char mask;
  54.  
  55.     mask = ~(1 << (irq_nr & 7));
  56.     save_flags(flags);
  57.     if (irq_nr < 8) {
  58.         cli();
  59.         cache_21 &= mask;
  60.         outb(cache_21,0x21);
  61.         restore_flags(flags);
  62.         return;
  63.     }
  64.     cli();
  65.     cache_A1 &= mask;
  66.     outb(cache_A1,0xA1);
  67.     restore_flags(flags);
  68. }
  69.  
  70. /*
  71.  * Initial irq handlers.
  72.  */
  73. struct irqaction {
  74.     void (*handler)(int, struct pt_regs *);
  75.     unsigned long flags;
  76.     unsigned long mask;
  77.     const char *name;
  78. };
  79.  
  80. static struct irqaction irq_action[16] = {
  81.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  82.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  83.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  84.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  85.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  86.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  87.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
  88.     { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
  89. };
  90.  
  91. int get_irq_list(char *buf)
  92. {
  93.     int i, len = 0;
  94.     struct irqaction * action = irq_action;
  95.  
  96.     for (i = 0 ; i < 16 ; i++, action++) {
  97.         if (!action->handler)
  98.             continue;
  99.         len += sprintf(buf+len, "%2d: %8d %c %s\n",
  100.             i, kstat.interrupts[i],
  101.             (action->flags & SA_INTERRUPT) ? '+' : ' ',
  102.             action->name);
  103.     }
  104.     return len;
  105. }
  106.  
  107. static inline void ack_irq(int irq)
  108. {
  109.     /* ACK the interrupt making it the lowest priority */
  110.     /*  First the slave .. */
  111.     if (irq > 7) {
  112.         outb(0xE0 | (irq - 8), 0xa0);
  113.         irq = 2;
  114.     }
  115.     /* .. then the master */
  116.     outb(0xE0 | irq, 0x20);
  117. }
  118.  
  119. static inline void mask_irq(int irq)
  120. {
  121.     if (irq < 8) {
  122.         cache_21 |= 1 << irq;
  123.         outb(cache_21, 0x21);
  124.     } else {
  125.         cache_A1 |= 1 << (irq - 8);
  126.         outb(cache_A1, 0xA1);
  127.     }
  128. }
  129.  
  130. static inline void unmask_irq(unsigned long irq)
  131. {
  132.     if (irq < 8) {
  133.         cache_21 &= ~(1 << irq);
  134.         outb(cache_21, 0x21);
  135.     } else {
  136.         cache_A1 &= ~(1 << (irq - 8));
  137.         outb(cache_A1, 0xA1);
  138.     }
  139. }
  140.  
  141. int request_irq(unsigned int irq, void (*handler)(int, struct pt_regs *),
  142.     unsigned long irqflags, const char * devname)
  143. {
  144.     struct irqaction * action;
  145.     unsigned long flags;
  146.  
  147.     if (irq > 15)
  148.         return -EINVAL;
  149.     action = irq + irq_action;
  150.     if (action->handler)
  151.         return -EBUSY;
  152.     if (!handler)
  153.         return -EINVAL;
  154.     save_flags(flags);
  155.     cli();
  156.     action->handler = handler;
  157.     action->flags = irqflags;
  158.     action->mask = 0;
  159.     action->name = devname;
  160.     if (irq < 8) {
  161.         if (irq) {
  162.             cache_21 &= ~(1<<irq);
  163.             outb(cache_21,0x21);
  164.         }
  165.     } else {
  166.         cache_21 &= ~(1<<2);
  167.         cache_A1 &= ~(1<<(irq-8));
  168.         outb(cache_21,0x21);
  169.         outb(cache_A1,0xA1);
  170.     }
  171.     restore_flags(flags);
  172.     return 0;
  173. }
  174.  
  175. void free_irq(unsigned int irq)
  176. {
  177.     struct irqaction * action = irq + irq_action;
  178.     unsigned long flags;
  179.  
  180.     if (irq > 15) {
  181.         printk("Trying to free IRQ%d\n", irq);
  182.         return;
  183.     }
  184.     if (!action->handler) {
  185.         printk("Trying to free free IRQ%d\n", irq);
  186.         return;
  187.     }
  188.     save_flags(flags);
  189.     cli();
  190.     mask_irq(irq);
  191.     action->handler = NULL;
  192.     action->flags = 0;
  193.     action->mask = 0;
  194.     action->name = NULL;
  195.     restore_flags(flags);
  196. }
  197.  
  198. static void handle_nmi(struct pt_regs * regs)
  199. {
  200.     printk("Whee.. NMI received. Probable hardware error\n");
  201.     printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461));
  202. }
  203.  
  204. static void unexpected_irq(int irq, struct pt_regs * regs)
  205. {
  206.     int i;
  207.  
  208.     printk("IO device interrupt, irq = %d\n", irq);
  209.     printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
  210.     printk("Expecting: ");
  211.     for (i = 0; i < 16; i++)
  212.         if (irq_action[i].handler)
  213.             printk("[%s:%d] ", irq_action[i].name, i);
  214.     printk("\n");
  215.     printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n",
  216.         inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa));
  217.     outb(0x0c, 0x3fc);
  218.     outb(0x0c, 0x2fc);
  219.     outb(0,0x61);
  220.     outb(0,0x461);
  221. }
  222.  
  223. static inline void handle_irq(int irq, struct pt_regs * regs)
  224. {
  225.     struct irqaction * action = irq + irq_action;
  226.  
  227.     kstat.interrupts[irq]++;
  228.     if (!action->handler) {
  229.         unexpected_irq(irq, regs);
  230.         return;
  231.     }
  232.     action->handler(irq, regs);
  233. }
  234.  
  235. static void local_device_interrupt(unsigned long vector, struct pt_regs * regs)
  236. {
  237.     switch (vector) {
  238.         /* com1: map to irq 4 */
  239.         case 0x900:
  240.             handle_irq(4, regs);
  241.             return;
  242.  
  243.         /* com2: map to irq 3 */
  244.         case 0x920:
  245.             handle_irq(3, regs);
  246.             return;
  247.  
  248.         /* keyboard: map to irq 1 */
  249.         case 0x980:
  250.             handle_irq(1, regs);
  251.             return;
  252.  
  253.         /* mouse: map to irq 12 */
  254.         case 0x990:
  255.             handle_irq(12, regs);
  256.             return;
  257.         default:
  258.             printk("Unknown local interrupt %lx\n", vector);
  259.     }
  260. }
  261.  
  262. /*
  263.  * The vector is 0x8X0 for EISA interrupt X, and 0x9X0 for the local
  264.  * motherboard interrupts.. This is for the Jensen.
  265.  *
  266.  *    0x660 - NMI
  267.  *
  268.  *    0x800 - IRQ0  interval timer (not used, as we use the RTC timer)
  269.  *    0x810 - IRQ1  line printer (duh..)
  270.  *    0x860 - IRQ6  floppy disk
  271.  *    0x8E0 - IRQ14 SCSI controller
  272.  *
  273.  *    0x900 - COM1
  274.  *    0x920 - COM2
  275.  *    0x980 - keyboard
  276.  *    0x990 - mouse
  277.  *
  278.  * The PCI version is more sane: it doesn't have the local interrupts at
  279.  * all, and has only normal PCI interrupts from devices. Happily it's easy
  280.  * enough to do a sane mapping from the Jensen.. Note that this means
  281.  * that we may have to do a hardware "ack" to a different interrupt than
  282.  * we report to the rest of the world..
  283.  */
  284. static void device_interrupt(unsigned long vector, struct pt_regs * regs)
  285. {
  286.     int irq, ack;
  287.     struct irqaction * action;
  288.  
  289.     if (vector == 0x660) {
  290.         handle_nmi(regs);
  291.         return;
  292.     }
  293.  
  294.     ack = irq = (vector - 0x800) >> 4;
  295. #ifndef CONFIG_PCI
  296.     if (vector >= 0x900) {
  297.         local_device_interrupt(vector, regs);
  298.         return;
  299.     }
  300.     /* irq1 is supposed to be the keyboard, silly Jensen */
  301.     if (irq == 1)
  302.         irq = 7;
  303. #endif
  304.     kstat.interrupts[irq]++;
  305.     action = irq_action + irq;
  306.     /* quick interrupts get executed with no extra overhead */
  307.     if (action->flags & SA_INTERRUPT) {
  308.         action->handler(irq, regs);
  309.         ack_irq(ack);
  310.         return;
  311.     }
  312.     /*
  313.      * For normal interrupts, we mask it out, and then ACK it.
  314.      * This way another (more timing-critical) interrupt can
  315.      * come through while we're doing this one.
  316.      *
  317.      * Note! A irq without a handler gets masked and acked, but
  318.      * never unmasked. The autoirq stuff depends on this (it looks
  319.      * at the masks before and after doing the probing).
  320.      */
  321.     mask_irq(ack);
  322.     ack_irq(ack);
  323.     if (!action->handler)
  324.         return;
  325.     action->handler(irq, regs);
  326.     unmask_irq(ack);
  327. }
  328.  
  329. /*
  330.  * Start listening for interrupts..
  331.  */
  332. unsigned int probe_irq_on(void)
  333. {
  334.     unsigned int i, irqs = 0, irqmask;
  335.     unsigned long delay;
  336.  
  337.     for (i = 15; i > 0; i--) {
  338.         if (!irq_action[i].handler) {
  339.             enable_irq(i);
  340.             irqs |= (1 << i);
  341.         }
  342.     }
  343.  
  344.     /* wait for spurious interrupts to mask themselves out again */
  345.     for (delay = jiffies + HZ/10; delay > jiffies; )
  346.         /* about 100 ms delay */;
  347.     
  348.     /* now filter out any obviously spurious interrupts */
  349.     irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int) cache_21;
  350.     irqs &= ~irqmask;
  351.     return irqs;
  352. }
  353.  
  354. /*
  355.  * Get the result of the IRQ probe.. A negative result means that
  356.  * we have several candidates (but we return the lowest-numbered
  357.  * one).
  358.  */
  359. int probe_irq_off(unsigned int irqs)
  360. {
  361.     unsigned int i, irqmask;
  362.     
  363.     irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
  364.     irqs &= irqmask;
  365.     if (!irqs)
  366.         return 0;
  367.     i = ffz(~irqs);
  368.     if (irqs != (1 << i))
  369.         i = -i;
  370.     return i;
  371. }
  372.  
  373. static void machine_check(unsigned long vector, unsigned long la_ptr, struct pt_regs * regs)
  374. {
  375.     printk("Machine check\n");
  376. }
  377.  
  378. asmlinkage void do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
  379.     unsigned long a3, unsigned long a4, unsigned long a5,
  380.     struct pt_regs regs)
  381. {
  382.     switch (type) {
  383.         case 0:
  384.             printk("Interprocessor interrupt? You must be kidding\n");
  385.             break;
  386.         case 1:
  387.             /* timer interrupt.. */
  388.             handle_irq(0, ®s);
  389.             return;
  390.         case 2:
  391.             machine_check(vector, la_ptr, ®s);
  392.             break;
  393.         case 3:
  394.             device_interrupt(vector, ®s);
  395.             return;
  396.         case 4:
  397.             printk("Performance counter interrupt\n");
  398.             break;;
  399.         default:
  400.             printk("Hardware intr %ld %lx? Huh?\n", type, vector);
  401.     }
  402.     printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
  403. }
  404.  
  405. extern asmlinkage void entInt(void);
  406.  
  407. void init_IRQ(void)
  408. {
  409.     wrent(entInt, 0);
  410.     dma_outb(0, DMA1_RESET_REG);
  411.     dma_outb(0, DMA2_RESET_REG);
  412.     dma_outb(0, DMA1_CLR_MASK_REG);
  413.     dma_outb(0, DMA2_CLR_MASK_REG);
  414. }
  415.