cia.c 4.0 KB

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