cia.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (C) 1996 Roman Zippel
  3. *
  4. * The concept of some functions bases on the original Amiga OS function
  5. *
  6. * This file is subject to the terms and conditions of the GNU General Public
  7. * License. See the file COPYING in the main directory of this archive
  8. * for more details.
  9. */
  10. #include <linux/types.h>
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/irq.h>
  15. #include <linux/kernel_stat.h>
  16. #include <linux/init.h>
  17. #include <asm/irq.h>
  18. #include <asm/amigahw.h>
  19. #include <asm/amigaints.h>
  20. struct ciabase {
  21. volatile struct CIA *cia;
  22. u_char icr_mask, icr_data;
  23. u_short int_mask;
  24. int handler_irq, cia_irq, server_irq;
  25. char *name;
  26. } ciaa_base = {
  27. &ciaa, 0, 0, IF_PORTS,
  28. IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
  29. IRQ_AMIGA_PORTS,
  30. "CIAA handler"
  31. }, ciab_base = {
  32. &ciab, 0, 0, IF_EXTER,
  33. IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB,
  34. IRQ_AMIGA_EXTER,
  35. "CIAB handler"
  36. };
  37. #define CIA_SET_BASE_ADJUST_IRQ(base, irq) \
  38. do { \
  39. if (irq >= IRQ_AMIGA_CIAB) { \
  40. base = &ciab_base; \
  41. irq -= IRQ_AMIGA_CIAB; \
  42. } else { \
  43. base = &ciaa_base; \
  44. irq -= IRQ_AMIGA_CIAA; \
  45. } \
  46. } while (0)
  47. /*
  48. * Cause or clear CIA interrupts, return old interrupt status.
  49. */
  50. static unsigned char cia_set_irq_private(struct ciabase *base,
  51. unsigned char mask)
  52. {
  53. u_char old;
  54. old = (base->icr_data |= base->cia->icr);
  55. if (mask & CIA_ICR_SETCLR)
  56. base->icr_data |= mask;
  57. else
  58. base->icr_data &= ~mask;
  59. if (base->icr_data & base->icr_mask)
  60. amiga_custom.intreq = IF_SETCLR | base->int_mask;
  61. return old & base->icr_mask;
  62. }
  63. unsigned char cia_set_irq(unsigned int irq, int set)
  64. {
  65. struct ciabase *base;
  66. unsigned char mask;
  67. if (irq >= IRQ_AMIGA_CIAB)
  68. mask = (1 << (irq - IRQ_AMIGA_CIAB));
  69. else
  70. mask = (1 << (irq - IRQ_AMIGA_CIAA));
  71. mask |= (set) ? CIA_ICR_SETCLR : 0;
  72. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  73. return cia_set_irq_private(base, mask);
  74. }
  75. unsigned char cia_get_irq_mask(unsigned int irq)
  76. {
  77. struct ciabase *base;
  78. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  79. return base->cia->icr;
  80. }
  81. /*
  82. * Enable or disable CIA interrupts, return old interrupt mask.
  83. */
  84. static unsigned char cia_able_irq_private(struct ciabase *base,
  85. unsigned char mask)
  86. {
  87. u_char old;
  88. old = base->icr_mask;
  89. base->icr_data |= base->cia->icr;
  90. base->cia->icr = mask;
  91. if (mask & CIA_ICR_SETCLR)
  92. base->icr_mask |= mask;
  93. else
  94. base->icr_mask &= ~mask;
  95. base->icr_mask &= CIA_ICR_ALL;
  96. if (base->icr_data & base->icr_mask)
  97. amiga_custom.intreq = IF_SETCLR | base->int_mask;
  98. return old;
  99. }
  100. unsigned char cia_able_irq(unsigned int irq, int enable)
  101. {
  102. struct ciabase *base;
  103. unsigned char mask;
  104. if (irq >= IRQ_AMIGA_CIAB)
  105. mask = (1 << (irq - IRQ_AMIGA_CIAB));
  106. else
  107. mask = (1 << (irq - IRQ_AMIGA_CIAA));
  108. mask |= (enable) ? CIA_ICR_SETCLR : 0;
  109. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  110. return cia_able_irq_private(base, mask);
  111. }
  112. static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
  113. {
  114. struct ciabase *base = (struct ciabase *)dev_id;
  115. irq_desc_t *desc;
  116. struct irqaction *action;
  117. int i;
  118. unsigned char ints;
  119. irq = base->cia_irq;
  120. desc = irq_desc + irq;
  121. ints = cia_set_irq_private(base, CIA_ICR_ALL);
  122. amiga_custom.intreq = base->int_mask;
  123. for (i = 0; i < CIA_IRQS; i++, irq++) {
  124. if (ints & 1) {
  125. kstat_cpu(0).irqs[irq]++;
  126. action = desc->action;
  127. action->handler(irq, action->dev_id, fp);
  128. }
  129. ints >>= 1;
  130. desc++;
  131. }
  132. amiga_do_irq_list(base->server_irq, fp);
  133. }
  134. void __init cia_init_IRQ(struct ciabase *base)
  135. {
  136. extern struct irqaction amiga_sys_irqaction[AUTO_IRQS];
  137. struct irqaction *action;
  138. /* clear any pending interrupt and turn off all interrupts */
  139. cia_set_irq_private(base, CIA_ICR_ALL);
  140. cia_able_irq_private(base, CIA_ICR_ALL);
  141. /* install CIA handler */
  142. action = &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO];
  143. action->handler = cia_handler;
  144. action->dev_id = base;
  145. action->name = base->name;
  146. setup_irq(base->handler_irq, &amiga_sys_irqaction[base->handler_irq-IRQ_AMIGA_AUTO]);
  147. amiga_custom.intena = IF_SETCLR | base->int_mask;
  148. }