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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.cia.c 1.7 05/21/01 00:48:24 cort
  3.  */
  4. /*
  5.  *  linux/arch/m68k/amiga/cia.c - CIA support
  6.  *
  7.  *  Copyright (C) 1996 Roman Zippel
  8.  *
  9.  *  The concept of some functions bases on the original Amiga OS function
  10.  *
  11.  * This file is subject to the terms and conditions of the GNU General Public
  12.  * License.  See the file COPYING in the main directory of this archive
  13.  * for more details.
  14.  */
  15. #include <linux/types.h>
  16. #include <linux/kernel.h>
  17. #include <linux/sched.h>
  18. #include <linux/errno.h>
  19. #include <linux/kernel_stat.h>
  20. #include <linux/init.h>
  21. #include <asm/irq.h>
  22. #include <asm/amigahw.h>
  23. #include <asm/amigaints.h>
  24. struct ciabase {
  25. volatile struct CIA *cia;
  26. u_char icr_mask, icr_data;
  27. u_short int_mask;
  28. int handler_irq, cia_irq, server_irq;
  29. char *name;
  30. irq_handler_t irq_list[CIA_IRQS];
  31. } ciaa_base = {
  32. &ciaa, 0, 0, IF_PORTS,
  33. IRQ_AMIGA_AUTO_2, IRQ_AMIGA_CIAA,
  34. IRQ_AMIGA_PORTS,
  35. "CIAA handler"
  36. }, ciab_base = {
  37. &ciab, 0, 0, IF_EXTER,
  38. IRQ_AMIGA_AUTO_6, IRQ_AMIGA_CIAB,
  39. IRQ_AMIGA_EXTER,
  40. "CIAB handler"
  41. };
  42. #define CIA_SET_BASE_ADJUST_IRQ(base, irq)
  43. do {
  44. if (irq >= IRQ_AMIGA_CIAB) {
  45. base = &ciab_base;
  46. irq -= IRQ_AMIGA_CIAB;
  47. } else {
  48. base = &ciaa_base;
  49. irq -= IRQ_AMIGA_CIAA;
  50. }
  51. } while (0)
  52. /*
  53.  *  Cause or clear CIA interrupts, return old interrupt status.
  54.  */
  55. static unsigned char cia_set_irq_private(struct ciabase *base,
  56.  unsigned char mask)
  57. {
  58. u_char old;
  59. old = (base->icr_data |= base->cia->icr);
  60. if (mask & CIA_ICR_SETCLR)
  61. base->icr_data |= mask;
  62. else
  63. base->icr_data &= ~mask;
  64. if (base->icr_data & base->icr_mask)
  65. custom.intreq = IF_SETCLR | base->int_mask;
  66. return old & base->icr_mask;
  67. }
  68. unsigned char cia_set_irq(unsigned int irq, int set)
  69. {
  70. struct ciabase *base;
  71. unsigned char mask;
  72. if (irq >= IRQ_AMIGA_CIAB)
  73. mask = (1 << (irq - IRQ_AMIGA_CIAB));
  74. else
  75. mask = (1 << (irq - IRQ_AMIGA_CIAA));
  76. mask |= (set) ? CIA_ICR_SETCLR : 0;
  77. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  78. return cia_set_irq_private(base, mask);
  79. }
  80. unsigned char cia_get_irq_mask(unsigned int irq)
  81. {
  82. struct ciabase *base;
  83. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  84. return base->cia->icr;
  85. }
  86. /*
  87.  *  Enable or disable CIA interrupts, return old interrupt mask,
  88.  *  interrupts will only be enabled if a handler exists
  89.  */
  90. static unsigned char cia_able_irq_private(struct ciabase *base,
  91.   unsigned char mask)
  92. {
  93. u_char old, tmp;
  94. int i;
  95. old = base->icr_mask;
  96. base->icr_data |= base->cia->icr;
  97. base->cia->icr = mask;
  98. if (mask & CIA_ICR_SETCLR)
  99. base->icr_mask |= mask;
  100. else
  101. base->icr_mask &= ~mask;
  102. base->icr_mask &= CIA_ICR_ALL;
  103. for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) {
  104. if ((tmp & base->icr_mask) && !base->irq_list[i].handler) {
  105. base->icr_mask &= ~tmp;
  106. base->cia->icr = tmp;
  107. }
  108. }
  109. if (base->icr_data & base->icr_mask)
  110. custom.intreq = IF_SETCLR | base->int_mask;
  111. return old;
  112. }
  113. unsigned char cia_able_irq(unsigned int irq, int enable)
  114. {
  115. struct ciabase *base;
  116. unsigned char mask;
  117. if (irq >= IRQ_AMIGA_CIAB)
  118. mask = (1 << (irq - IRQ_AMIGA_CIAB));
  119. else
  120. mask = (1 << (irq - IRQ_AMIGA_CIAA));
  121. mask |= (enable) ? CIA_ICR_SETCLR : 0;
  122. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  123. return cia_able_irq_private(base, mask);
  124. }
  125. int cia_request_irq(unsigned int irq,
  126.                     void (*handler)(int, void *, struct pt_regs *),
  127.                     unsigned long flags, const char *devname, void *dev_id)
  128. {
  129. u_char mask;
  130. struct ciabase *base;
  131. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  132. base->irq_list[irq].handler = handler;
  133. base->irq_list[irq].flags   = flags;
  134. base->irq_list[irq].dev_id  = dev_id;
  135. base->irq_list[irq].devname = devname;
  136. /* enable the interrupt */
  137. mask = 1 << irq;
  138. cia_set_irq_private(base, mask);
  139. cia_able_irq_private(base, CIA_ICR_SETCLR | mask);
  140. return 0;
  141. }
  142. void cia_free_irq(unsigned int irq, void *dev_id)
  143. {
  144. struct ciabase *base;
  145. CIA_SET_BASE_ADJUST_IRQ(base, irq);
  146. if (base->irq_list[irq].dev_id != dev_id)
  147. printk("%s: removing probably wrong IRQ %i from %sn",
  148.        __FUNCTION__, base->cia_irq + irq,
  149.        base->irq_list[irq].devname);
  150. base->irq_list[irq].handler = NULL;
  151. base->irq_list[irq].flags   = 0;
  152. cia_able_irq_private(base, 1 << irq);
  153. }
  154. static void cia_handler(int irq, void *dev_id, struct pt_regs *fp)
  155. {
  156. struct ciabase *base = (struct ciabase *)dev_id;
  157. int mach_irq, i;
  158. unsigned char ints;
  159. mach_irq = base->cia_irq;
  160. irq = SYS_IRQS + mach_irq;
  161. ints = cia_set_irq_private(base, CIA_ICR_ALL);
  162. custom.intreq = base->int_mask;
  163. for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) {
  164. if (ints & 1) {
  165. kstat.irqs[0][irq]++;
  166. base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp);
  167. }
  168. ints >>= 1;
  169. }
  170. amiga_do_irq_list(base->server_irq, fp);
  171. }
  172. void __init cia_init_IRQ(struct ciabase *base)
  173. {
  174. int i;
  175. /* init isr handlers */
  176. for (i = 0; i < CIA_IRQS; i++) {
  177. base->irq_list[i].handler = NULL;
  178. base->irq_list[i].flags   = 0;
  179. }
  180. /* clear any pending interrupt and turn off all interrupts */
  181. cia_set_irq_private(base, CIA_ICR_ALL);
  182. cia_able_irq_private(base, CIA_ICR_ALL);
  183. /* install CIA handler */
  184. request_irq(base->handler_irq, cia_handler, 0, base->name, base);
  185. custom.intena = IF_SETCLR | base->int_mask;
  186. }
  187. int cia_get_irq_list(struct ciabase *base, char *buf)
  188. {
  189. int i, j, len = 0;
  190. j = base->cia_irq;
  191. for (i = 0; i < CIA_IRQS; i++) {
  192. len += sprintf(buf+len, "cia  %2d: %10d ", j + i,
  193.        kstat.irqs[0][SYS_IRQS + j + i]);
  194. len += sprintf(buf+len, "  ");
  195. len += sprintf(buf+len, "%sn", base->irq_list[i].devname);
  196. }
  197. return len;
  198. }