cia.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:4k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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