old-irq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Code to handle x86 style IRQs plus some generic interrupt stuff.
  7.  *
  8.  * Copyright (C) 1992 Linus Torvalds
  9.  * Copyright (C) 1994 - 2001 Ralf Baechle
  10.  *
  11.  * Old rotten IRQ code.  To be killed as soon as everybody had converted or
  12.  * in 2.5.0, whatever comes first.
  13.  */
  14. #include <linux/config.h>
  15. #include <linux/errno.h>
  16. #include <linux/init.h>
  17. #include <linux/kernel_stat.h>
  18. #include <linux/module.h>
  19. #include <linux/signal.h>
  20. #include <linux/sched.h>
  21. #include <linux/types.h>
  22. #include <linux/interrupt.h>
  23. #include <linux/ioport.h>
  24. #include <linux/timex.h>
  25. #include <linux/slab.h>
  26. #include <linux/random.h>
  27. #include <asm/bitops.h>
  28. #include <asm/bootinfo.h>
  29. #include <asm/io.h>
  30. #include <asm/irq.h>
  31. #include <asm/mipsregs.h>
  32. #include <asm/system.h>
  33. #include <asm/nile4.h>
  34. /*
  35.  * The board specific setup routine sets irq_setup to point to a board
  36.  * specific setup routine.
  37.  */
  38. void (*irq_setup)(void);
  39. /*
  40.  * Linux has a controller-independent x86 interrupt architecture.
  41.  * every controller has a 'controller-template', that is used
  42.  * by the main code to do the right thing. Each driver-visible
  43.  * interrupt source is transparently wired to the apropriate
  44.  * controller. Thus drivers need not be aware of the
  45.  * interrupt-controller.
  46.  *
  47.  * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
  48.  * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
  49.  * (IO-APICs assumed to be messaging to Pentium local-APICs)
  50.  *
  51.  * the code is designed to be easily extended with new/different
  52.  * interrupt controllers, without having to do assembly magic.
  53.  */
  54. /*
  55.  * This contains the irq mask for both 8259A irq controllers, it's an
  56.  * int so we can deal with the third PIC in some systems like the RM300.
  57.  * (XXX This is broken for big endian.)
  58.  */
  59. static unsigned int cached_irq_mask = 0xffff;
  60. #define __byte(x,y) (((unsigned char *)&(y))[x])
  61. #define __word(x,y) (((unsigned short *)&(y))[x])
  62. #define __long(x,y) (((unsigned int *)&(y))[x])
  63. #define cached_21       (__byte(0,cached_irq_mask))
  64. #define cached_A1       (__byte(1,cached_irq_mask))
  65. volatile unsigned long irq_err_count;
  66. /*
  67.  * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and
  68.  * PCI devices.  Other onboard hardware needs specific routines.
  69.  */
  70. static inline void mask_irq(unsigned int irq)
  71. {
  72. cached_irq_mask |= 1 << irq;
  73. if (irq & 8) {
  74. outb(cached_A1, 0xa1);
  75. } else {
  76. outb(cached_21, 0x21);
  77. }
  78. }
  79. static inline void unmask_irq(unsigned int irq)
  80. {
  81. cached_irq_mask &= ~(1 << irq);
  82. if (irq & 8) {
  83. outb(cached_A1, 0xa1);
  84. } else {
  85. outb(cached_21, 0x21);
  86. }
  87. }
  88. void i8259_disable_irq(unsigned int irq_nr)
  89. {
  90. unsigned long flags;
  91. save_and_cli(flags);
  92. mask_irq(irq_nr);
  93. restore_flags(flags);
  94. }
  95. void i8259_enable_irq(unsigned int irq_nr)
  96. {
  97. unsigned long flags;
  98. save_and_cli(flags);
  99. unmask_irq(irq_nr);
  100. restore_flags(flags);
  101. }
  102. static struct irqaction *irq_action[NR_IRQS] = {
  103. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  104. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  105. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  106. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  107. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  108. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  109. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  110. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
  111. };
  112. int get_irq_list(char *buf)
  113. {
  114. int i, len = 0;
  115. struct irqaction * action;
  116. for (i = 0 ; i < 32 ; i++) {
  117. action = irq_action[i];
  118. if (!action)
  119. continue;
  120. len += sprintf(buf+len, "%2d: %8d %c %s",
  121. i, kstat.irqs[0][i],
  122. (action->flags & SA_INTERRUPT) ? '+' : ' ',
  123. action->name);
  124. for (action=action->next; action; action = action->next) {
  125. len += sprintf(buf+len, ",%s %s",
  126. (action->flags & SA_INTERRUPT) ? " +" : "",
  127. action->name);
  128. }
  129. len += sprintf(buf+len, "n");
  130. }
  131. return len;
  132. }
  133. static inline void i8259_mask_and_ack_irq(int irq)
  134. {
  135. cached_irq_mask |= 1 << irq;
  136. if (irq & 8) {
  137. inb(0xa1);
  138. outb(cached_A1, 0xa1);
  139. outb(0x62, 0x20); /* Specific EOI to cascade */
  140.                 outb(0x20, 0xa0);
  141.         } else {
  142. inb(0x21);
  143. outb(cached_21, 0x21);
  144. outb(0x20, 0x20);
  145.         }
  146. }
  147. asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs)
  148. {
  149. struct irqaction *action;
  150. int do_random, cpu;
  151. cpu = smp_processor_id();
  152. irq_enter(cpu, irq);
  153. if (irq >= 16)
  154. goto out;
  155. i8259_mask_and_ack_irq(irq);
  156. kstat.irqs[cpu][irq]++;
  157. action = *(irq + irq_action);
  158. if (!action)
  159. goto out;
  160. if (!(action->flags & SA_INTERRUPT))
  161. __sti();
  162. action = *(irq + irq_action);
  163. do_random = 0;
  164.         do {
  165. do_random |= action->flags;
  166. action->handler(irq, action->dev_id, regs);
  167. action = action->next;
  168.         } while (action);
  169. if (do_random & SA_SAMPLE_RANDOM)
  170. add_interrupt_randomness(irq);
  171. __cli();
  172. unmask_irq (irq);
  173. out:
  174. irq_exit(cpu, irq);
  175. }
  176. /*
  177.  * do_IRQ handles IRQ's that have been installed without the
  178.  * SA_INTERRUPT flag: it uses the full signal-handling return
  179.  * and runs with other interrupts enabled. All relatively slow
  180.  * IRQ's should use this format: notably the keyboard/timer
  181.  * routines.
  182.  */
  183. asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
  184. {
  185. struct irqaction *action;
  186. int do_random, cpu;
  187. cpu = smp_processor_id();
  188. irq_enter(cpu, irq);
  189. kstat.irqs[cpu][irq]++;
  190. action = *(irq + irq_action);
  191. if (action) {
  192. if (!(action->flags & SA_INTERRUPT))
  193. __sti();
  194. action = *(irq + irq_action);
  195. do_random = 0;
  196.          do {
  197. do_random |= action->flags;
  198. action->handler(irq, action->dev_id, regs);
  199. action = action->next;
  200.          } while (action);
  201. if (do_random & SA_SAMPLE_RANDOM)
  202. add_interrupt_randomness(irq);
  203. __cli();
  204. }
  205. irq_exit(cpu, irq);
  206. if (softirq_pending(cpu))
  207. do_softirq();
  208. /* unmasking and bottom half handling is done magically for us. */
  209. }
  210. int i8259_setup_irq(int irq, struct irqaction * new)
  211. {
  212. int shared = 0;
  213. struct irqaction *old, **p;
  214. unsigned long flags;
  215. p = irq_action + irq;
  216. if ((old = *p) != NULL) {
  217. /* Can't share interrupts unless both agree to */
  218. if (!(old->flags & new->flags & SA_SHIRQ))
  219. return -EBUSY;
  220. /* Can't share interrupts unless both are same type */
  221. if ((old->flags ^ new->flags) & SA_INTERRUPT)
  222. return -EBUSY;
  223. /* add new interrupt at end of irq queue */
  224. do {
  225. p = &old->next;
  226. old = *p;
  227. } while (old);
  228. shared = 1;
  229. }
  230. if (new->flags & SA_SAMPLE_RANDOM)
  231. rand_initialize_irq(irq);
  232. save_and_cli(flags);
  233. *p = new;
  234. if (!shared) {
  235. if (is_i8259_irq(irq))
  236.     unmask_irq(irq);
  237. #if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476))
  238. else
  239.     nile4_enable_irq(irq_to_nile4(irq));
  240. #endif
  241. }
  242. restore_flags(flags);
  243. return 0;
  244. }
  245. /*
  246.  * Request_interrupt and free_interrupt ``sort of'' handle interrupts of
  247.  * non i8259 devices.  They will have to be replaced by architecture
  248.  * specific variants.  For now we still use this as broken as it is because
  249.  * it used to work ...
  250.  */
  251. int request_irq(unsigned int irq,
  252. void (*handler)(int, void *, struct pt_regs *),
  253. unsigned long irqflags, const char * devname, void *dev_id)
  254. {
  255. int retval;
  256. struct irqaction * action;
  257. if (irq >= 32)
  258. return -EINVAL;
  259. if (!handler)
  260. return -EINVAL;
  261. action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
  262. if (!action)
  263. return -ENOMEM;
  264. action->handler = handler;
  265. action->flags = irqflags;
  266. action->mask = 0;
  267. action->name = devname;
  268. action->next = NULL;
  269. action->dev_id = dev_id;
  270. retval = i8259_setup_irq(irq, action);
  271. if (retval)
  272. kfree(action);
  273. return retval;
  274. }
  275. void free_irq(unsigned int irq, void *dev_id)
  276. {
  277. struct irqaction * action, **p;
  278. unsigned long flags;
  279. if (irq > 31) {
  280. printk("Trying to free IRQ%dn",irq);
  281. return;
  282. }
  283. for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
  284. if (action->dev_id != dev_id)
  285. continue;
  286. /* Found it - now free it */
  287. save_and_cli(flags);
  288. *p = action->next;
  289. if (!irq[irq_action])
  290. mask_irq(irq);
  291. restore_flags(flags);
  292. kfree(action);
  293. return;
  294. }
  295. printk("Trying to free free IRQ%dn",irq);
  296. }
  297. unsigned long probe_irq_on (void)
  298. {
  299. unsigned int i, irqs = 0;
  300. unsigned long delay;
  301. /* first, enable any unassigned (E)ISA irqs */
  302. for (i = 15; i > 0; i--) {
  303. if (!irq_action[i]) {
  304. i8259_enable_irq(i);
  305. irqs |= (1 << i);
  306. }
  307. }
  308. /* wait for spurious interrupts to mask themselves out again */
  309. for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
  310. /* about 100ms delay */;
  311. /* now filter out any obviously spurious interrupts */
  312. return irqs & ~cached_irq_mask;
  313. }
  314. int probe_irq_off (unsigned long irqs)
  315. {
  316. unsigned int i;
  317. #ifdef DEBUG
  318. printk("probe_irq_off: irqs=0x%04x irqmask=0x%04xn", irqs, irqmask);
  319. #endif
  320. irqs &= cached_irq_mask;
  321. if (!irqs)
  322. return 0;
  323. i = ffz(~irqs);
  324. if (irqs != (irqs & (1 << i)))
  325. i = -i;
  326. return i;
  327. }
  328. void __init i8259_init(void)
  329. {
  330. /* Init master interrupt controller */
  331. outb(0x11, 0x20); /* Start init sequence */
  332. outb(0x00, 0x21); /* Vector base */
  333. outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
  334. outb(0x01, 0x21); /* Select 8086 mode */
  335. outb(0xff, 0x21); /* Mask all */
  336. /* Init slave interrupt controller */
  337. outb(0x11, 0xa0); /* Start init sequence */
  338. outb(0x08, 0xa1); /* Vector base */
  339. outb(0x02, 0xa1); /* edge triggered, Cascade (slave) on IRQ2 */
  340. outb(0x01, 0xa1); /* Select 8086 mode */
  341. outb(0xff, 0xa1); /* Mask all */
  342. outb(cached_A1, 0xa1);
  343. outb(cached_21, 0x21);
  344. }
  345. void __init init_IRQ(void)
  346. {
  347. /* i8259_init(); */
  348. irq_setup();
  349. }
  350. EXPORT_SYMBOL(free_irq);
  351. EXPORT_SYMBOL(request_irq);