amiints.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. * Amiga Linux interrupt handling code
  3. *
  4. * This file is subject to the terms and conditions of the GNU General Public
  5. * License. See the file COPYING in the main directory of this archive
  6. * for more details.
  7. */
  8. #include <linux/init.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/errno.h>
  11. #ifdef CONFIG_GENERIC_HARDIRQS
  12. #include <linux/irq.h>
  13. #endif
  14. #include <asm/irq.h>
  15. #include <asm/traps.h>
  16. #include <asm/amigahw.h>
  17. #include <asm/amigaints.h>
  18. #include <asm/amipcmcia.h>
  19. /*
  20. * Enable/disable a particular machine specific interrupt source.
  21. * Note that this may affect other interrupts in case of a shared interrupt.
  22. * This function should only be called for a _very_ short time to change some
  23. * internal data, that may not be changed by the interrupt at the same time.
  24. */
  25. static void amiga_irq_enable(struct irq_data *data)
  26. {
  27. amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER));
  28. }
  29. static void amiga_irq_disable(struct irq_data *data)
  30. {
  31. amiga_custom.intena = 1 << (data->irq - IRQ_USER);
  32. }
  33. static struct irq_chip amiga_irq_chip = {
  34. .name = "amiga",
  35. .irq_enable = amiga_irq_enable,
  36. .irq_disable = amiga_irq_disable,
  37. };
  38. /*
  39. * The builtin Amiga hardware interrupt handlers.
  40. */
  41. #ifdef CONFIG_GENERIC_HARDIRQS
  42. static void ami_int1(unsigned int irq, struct irq_desc *desc)
  43. {
  44. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  45. /* if serial transmit buffer empty, interrupt */
  46. if (ints & IF_TBE) {
  47. amiga_custom.intreq = IF_TBE;
  48. generic_handle_irq(IRQ_AMIGA_TBE);
  49. }
  50. /* if floppy disk transfer complete, interrupt */
  51. if (ints & IF_DSKBLK) {
  52. amiga_custom.intreq = IF_DSKBLK;
  53. generic_handle_irq(IRQ_AMIGA_DSKBLK);
  54. }
  55. /* if software interrupt set, interrupt */
  56. if (ints & IF_SOFT) {
  57. amiga_custom.intreq = IF_SOFT;
  58. generic_handle_irq(IRQ_AMIGA_SOFT);
  59. }
  60. }
  61. static void ami_int3(unsigned int irq, struct irq_desc *desc)
  62. {
  63. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  64. /* if a blitter interrupt */
  65. if (ints & IF_BLIT) {
  66. amiga_custom.intreq = IF_BLIT;
  67. generic_handle_irq(IRQ_AMIGA_BLIT);
  68. }
  69. /* if a copper interrupt */
  70. if (ints & IF_COPER) {
  71. amiga_custom.intreq = IF_COPER;
  72. generic_handle_irq(IRQ_AMIGA_COPPER);
  73. }
  74. /* if a vertical blank interrupt */
  75. if (ints & IF_VERTB) {
  76. amiga_custom.intreq = IF_VERTB;
  77. generic_handle_irq(IRQ_AMIGA_VERTB);
  78. }
  79. }
  80. static void ami_int4(unsigned int irq, struct irq_desc *desc)
  81. {
  82. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  83. /* if audio 0 interrupt */
  84. if (ints & IF_AUD0) {
  85. amiga_custom.intreq = IF_AUD0;
  86. generic_handle_irq(IRQ_AMIGA_AUD0);
  87. }
  88. /* if audio 1 interrupt */
  89. if (ints & IF_AUD1) {
  90. amiga_custom.intreq = IF_AUD1;
  91. generic_handle_irq(IRQ_AMIGA_AUD1);
  92. }
  93. /* if audio 2 interrupt */
  94. if (ints & IF_AUD2) {
  95. amiga_custom.intreq = IF_AUD2;
  96. generic_handle_irq(IRQ_AMIGA_AUD2);
  97. }
  98. /* if audio 3 interrupt */
  99. if (ints & IF_AUD3) {
  100. amiga_custom.intreq = IF_AUD3;
  101. generic_handle_irq(IRQ_AMIGA_AUD3);
  102. }
  103. }
  104. static void ami_int5(unsigned int irq, struct irq_desc *desc)
  105. {
  106. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  107. /* if serial receive buffer full interrupt */
  108. if (ints & IF_RBF) {
  109. /* acknowledge of IF_RBF must be done by the serial interrupt */
  110. generic_handle_irq(IRQ_AMIGA_RBF);
  111. }
  112. /* if a disk sync interrupt */
  113. if (ints & IF_DSKSYN) {
  114. amiga_custom.intreq = IF_DSKSYN;
  115. generic_handle_irq(IRQ_AMIGA_DSKSYN);
  116. }
  117. }
  118. #else /* !CONFIG_GENERIC_HARDIRQS */
  119. static irqreturn_t ami_int1(int irq, void *dev_id)
  120. {
  121. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  122. /* if serial transmit buffer empty, interrupt */
  123. if (ints & IF_TBE) {
  124. amiga_custom.intreq = IF_TBE;
  125. generic_handle_irq(IRQ_AMIGA_TBE);
  126. }
  127. /* if floppy disk transfer complete, interrupt */
  128. if (ints & IF_DSKBLK) {
  129. amiga_custom.intreq = IF_DSKBLK;
  130. generic_handle_irq(IRQ_AMIGA_DSKBLK);
  131. }
  132. /* if software interrupt set, interrupt */
  133. if (ints & IF_SOFT) {
  134. amiga_custom.intreq = IF_SOFT;
  135. generic_handle_irq(IRQ_AMIGA_SOFT);
  136. }
  137. return IRQ_HANDLED;
  138. }
  139. static irqreturn_t ami_int3(int irq, void *dev_id)
  140. {
  141. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  142. /* if a blitter interrupt */
  143. if (ints & IF_BLIT) {
  144. amiga_custom.intreq = IF_BLIT;
  145. generic_handle_irq(IRQ_AMIGA_BLIT);
  146. }
  147. /* if a copper interrupt */
  148. if (ints & IF_COPER) {
  149. amiga_custom.intreq = IF_COPER;
  150. generic_handle_irq(IRQ_AMIGA_COPPER);
  151. }
  152. /* if a vertical blank interrupt */
  153. if (ints & IF_VERTB) {
  154. amiga_custom.intreq = IF_VERTB;
  155. generic_handle_irq(IRQ_AMIGA_VERTB);
  156. }
  157. return IRQ_HANDLED;
  158. }
  159. static irqreturn_t ami_int4(int irq, void *dev_id)
  160. {
  161. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  162. /* if audio 0 interrupt */
  163. if (ints & IF_AUD0) {
  164. amiga_custom.intreq = IF_AUD0;
  165. generic_handle_irq(IRQ_AMIGA_AUD0);
  166. }
  167. /* if audio 1 interrupt */
  168. if (ints & IF_AUD1) {
  169. amiga_custom.intreq = IF_AUD1;
  170. generic_handle_irq(IRQ_AMIGA_AUD1);
  171. }
  172. /* if audio 2 interrupt */
  173. if (ints & IF_AUD2) {
  174. amiga_custom.intreq = IF_AUD2;
  175. generic_handle_irq(IRQ_AMIGA_AUD2);
  176. }
  177. /* if audio 3 interrupt */
  178. if (ints & IF_AUD3) {
  179. amiga_custom.intreq = IF_AUD3;
  180. generic_handle_irq(IRQ_AMIGA_AUD3);
  181. }
  182. return IRQ_HANDLED;
  183. }
  184. static irqreturn_t ami_int5(int irq, void *dev_id)
  185. {
  186. unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
  187. /* if serial receive buffer full interrupt */
  188. if (ints & IF_RBF) {
  189. /* acknowledge of IF_RBF must be done by the serial interrupt */
  190. generic_handle_irq(IRQ_AMIGA_RBF);
  191. }
  192. /* if a disk sync interrupt */
  193. if (ints & IF_DSKSYN) {
  194. amiga_custom.intreq = IF_DSKSYN;
  195. generic_handle_irq(IRQ_AMIGA_DSKSYN);
  196. }
  197. return IRQ_HANDLED;
  198. }
  199. #endif /* !CONFIG_GENERIC_HARDIRQS */
  200. /*
  201. * void amiga_init_IRQ(void)
  202. *
  203. * Parameters: None
  204. *
  205. * Returns: Nothing
  206. *
  207. * This function should be called during kernel startup to initialize
  208. * the amiga IRQ handling routines.
  209. */
  210. void __init amiga_init_IRQ(void)
  211. {
  212. #ifdef CONFIG_GENERIC_HARDIRQS
  213. m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
  214. AMI_STD_IRQS);
  215. irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
  216. irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
  217. irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
  218. irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
  219. #else /* !CONFIG_GENERIC_HARDIRQS */
  220. if (request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL))
  221. pr_err("Couldn't register int%d\n", 1);
  222. if (request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL))
  223. pr_err("Couldn't register int%d\n", 3);
  224. if (request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL))
  225. pr_err("Couldn't register int%d\n", 4);
  226. if (request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL))
  227. pr_err("Couldn't register int%d\n", 5);
  228. m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
  229. AMI_STD_IRQS);
  230. #endif /* !CONFIG_GENERIC_HARDIRQS */
  231. /* turn off PCMCIA interrupts */
  232. if (AMIGAHW_PRESENT(PCMCIA))
  233. gayle.inten = GAYLE_IRQ_IDE;
  234. /* turn off all interrupts and enable the master interrupt bit */
  235. amiga_custom.intena = 0x7fff;
  236. amiga_custom.intreq = 0x7fff;
  237. amiga_custom.intena = IF_SETCLR | IF_INTEN;
  238. cia_init_IRQ(&ciaa_base);
  239. cia_init_IRQ(&ciab_base);
  240. }