cia.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * linux/arch/m68k/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/errno.h>
  16. #include <linux/kernel_stat.h>
  17. #include <linux/init.h>
  18. #include <linux/seq_file.h>
  19. #include <linux/interrupt.h>
  20. #include <asm/irq.h>
  21. #include <asm/amigahw.h>
  22. #include <asm/amigaints.h>
  23. struct ciabase {
  24. volatile struct CIA *cia;
  25. unsigned char icr_mask, icr_data;
  26. unsigned short int_mask;
  27. int handler_irq, cia_irq, server_irq;
  28. char *name;
  29. irq_handler_t irq_list[CIA_IRQS];
  30. } ciaa_base = {
  31. .cia = &ciaa,
  32. .int_mask = IF_PORTS,
  33. .handler_irq = IRQ_AMIGA_AUTO_2,
  34. .cia_irq = IRQ_AMIGA_CIAA,
  35. .server_irq = IRQ_AMIGA_PORTS,
  36. .name = "CIAA handler"
  37. }, ciab_base = {
  38. .cia = &ciab,
  39. .int_mask = IF_EXTER,
  40. .handler_irq = IRQ_AMIGA_AUTO_6,
  41. .cia_irq = IRQ_AMIGA_CIAB,
  42. .server_irq = IRQ_AMIGA_EXTER,
  43. .name = "CIAB handler"
  44. };
  45. /*
  46. * Cause or clear CIA interrupts, return old interrupt status.
  47. */
  48. unsigned char cia_set_irq(struct ciabase *base, unsigned char mask)
  49. {
  50. unsigned char old;
  51. old = (base->icr_data |= base->cia->icr);
  52. if (mask & CIA_ICR_SETCLR)
  53. base->icr_data |= mask;
  54. else
  55. base->icr_data &= ~mask;
  56. if (base->icr_data & base->icr_mask)
  57. custom.intreq = IF_SETCLR | base->int_mask;
  58. return old & base->icr_mask;
  59. }
  60. /*
  61. * Enable or disable CIA interrupts, return old interrupt mask,
  62. * interrupts will only be enabled if a handler exists
  63. */
  64. unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
  65. {
  66. unsigned char old, tmp;
  67. int i;
  68. old = base->icr_mask;
  69. base->icr_data |= base->cia->icr;
  70. base->cia->icr = mask;
  71. if (mask & CIA_ICR_SETCLR)
  72. base->icr_mask |= mask;
  73. else
  74. base->icr_mask &= ~mask;
  75. base->icr_mask &= CIA_ICR_ALL;
  76. for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
  77. if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
  78. base->icr_mask &= ~tmp;
  79. base->cia->icr = tmp;
  80. }
  81. }
  82. if (base->icr_data & base->icr_mask)
  83. custom.intreq = IF_SETCLR | base->int_mask;
  84. return old;
  85. }
  86. int cia_request_irq(struct ciabase *base, unsigned int irq,
  87. irqreturn_t (*handler)(int, void *, struct pt_regs *),
  88. unsigned long flags, const char *devname, void *dev_id)
  89. {
  90. unsigned char mask;
  91. base->irq_list[irq].handler = handler;
  92. base->irq_list[irq].flags = flags;
  93. base->irq_list[irq].dev_id = dev_id;
  94. base->irq_list[irq].devname = devname;
  95. /* enable the interrupt */
  96. mask = 1 << irq;
  97. cia_set_irq(base, mask);
  98. cia_able_irq(base, CIA_ICR_SETCLR | mask);
  99. return 0;
  100. }
  101. void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id)
  102. {
  103. if (base->irq_list[irq].dev_id != dev_id)
  104. printk("%s: removing probably wrong IRQ %i from %s\n",
  105. __FUNCTION__, base->cia_irq + irq,
  106. base->irq_list[irq].devname);
  107. base->irq_list[irq].handler = NULL;
  108. base->irq_list[irq].flags = 0;
  109. cia_able_irq(base, 1 << irq);
  110. }
  111. static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp)
  112. {
  113. struct ciabase *base = (struct ciabase *)dev_id;
  114. int mach_irq, i;
  115. unsigned char ints;
  116. mach_irq = base->cia_irq;
  117. irq = SYS_IRQS + mach_irq;
  118. ints = cia_set_irq(base, CIA_ICR_ALL);
  119. custom.intreq = base->int_mask;
  120. for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
  121. if (ints & 1) {
  122. kstat_cpu(0).irqs[irq]++;
  123. base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
  124. }
  125. ints >>= 1;
  126. }
  127. amiga_do_irq_list(base->server_irq, fp);
  128. return IRQ_HANDLED;
  129. }
  130. void __init cia_init_IRQ(struct ciabase *base)
  131. {
  132. int i;
  133. /* init isr handlers */
  134. for (i = 0; i < CIA_IRQS; i++) {
  135. base->irq_list[i].handler = NULL;
  136. base->irq_list[i].flags = 0;
  137. }
  138. /* clear any pending interrupt and turn off all interrupts */
  139. cia_set_irq(base, CIA_ICR_ALL);
  140. cia_able_irq(base, CIA_ICR_ALL);
  141. /* install CIA handler */
  142. request_irq(base->handler_irq, cia_handler, 0, base->name, base);
  143. custom.intena = IF_SETCLR | base->int_mask;
  144. }
  145. int cia_get_irq_list(struct ciabase *base, struct seq_file *p)
  146. {
  147. int i, j;
  148. j = base->cia_irq;
  149. for (i = 0; i < CIA_IRQS; i++) {
  150. seq_printf(p, "cia %2d: %10d ", j + i,
  151. kstat_cpu(0).irqs[SYS_IRQS + j + i]);
  152. seq_puts(p, " ");
  153. seq_printf(p, "%s\n", base->irq_list[i].devname);
  154. }
  155. return 0;
  156. }