amiints.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: %F% %I% %G% %U% %#%
  3.  */
  4. /*
  5.  * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
  6.  *
  7.  * This file is subject to the terms and conditions of the GNU General Public
  8.  * License.  See the file COPYING in the main directory of this archive
  9.  * for more details.
  10.  *
  11.  * 11/07/96: rewritten interrupt handling, irq lists are exists now only for
  12.  *           this sources where it makes sense (VERTB/PORTS/EXTER) and you must
  13.  *           be careful that dev_id for this sources is unique since this the
  14.  *           only possibility to distinguish between different handlers for
  15.  *           free_irq. irq lists also have different irq flags:
  16.  *           - IRQ_FLG_FAST: handler is inserted at top of list (after other
  17.  *                           fast handlers)
  18.  *           - IRQ_FLG_SLOW: handler is inserted at bottom of list and before
  19.  *                           they're executed irq level is set to the previous
  20.  *                           one, but handlers don't need to be reentrant, if
  21.  *                           reentrance occurred, slow handlers will be just
  22.  *                           called again.
  23.  *           The whole interrupt handling for CIAs is moved to cia.c
  24.  *           /Roman Zippel
  25.  *
  26.  * 07/08/99: rewamp of the interrupt handling - we now have two types of
  27.  *           interrupts, normal and fast handlers, fast handlers being
  28.  *           marked with SA_INTERRUPT and runs with all other interrupts
  29.  *           disabled. Normal interrupts disable their own source but
  30.  *           run with all other interrupt sources enabled.
  31.  *           PORTS and EXTER interrupts are always shared even if the
  32.  *           drivers do not explicitly mark this when calling
  33.  *           request_irq which they really should do.
  34.  *           This is similar to the way interrupts are handled on all
  35.  *           other architectures and makes a ton of sense besides
  36.  *           having the advantage of making it easier to share
  37.  *           drivers.
  38.  *           /Jes
  39.  */
  40. #include <linux/config.h>
  41. #include <linux/types.h>
  42. #include <linux/kernel.h>
  43. #include <linux/sched.h>
  44. #include <linux/interrupt.h>
  45. #include <linux/irq.h>
  46. #include <linux/kernel_stat.h>
  47. #include <linux/init.h>
  48. #include <asm/system.h>
  49. #include <asm/irq.h>
  50. #include <asm/traps.h>
  51. #include <asm/amigahw.h>
  52. #include <asm/amigaints.h>
  53. #include <asm/amipcmcia.h>
  54. #ifdef CONFIG_APUS
  55. #include <asm/amigappc.h>
  56. #endif
  57. extern int cia_request_irq(int irq,
  58.                            void (*handler)(int, void *, struct pt_regs *),
  59.                            unsigned long flags, const char *devname, void *dev_id);
  60. extern void cia_free_irq(unsigned int irq, void *dev_id);
  61. extern void cia_init_IRQ(struct ciabase *base);
  62. extern int cia_get_irq_list(struct ciabase *base, char *buf);
  63. unsigned short ami_intena_vals[AMI_STD_IRQS] = {
  64. IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT,
  65. IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER
  66. };
  67. static const unsigned char ami_servers[AMI_STD_IRQS] = {
  68. 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
  69. };
  70. static short ami_ablecount[AMI_IRQS];
  71. static void ami_badint(int irq, void *dev_id, struct pt_regs *fp)
  72. {
  73. /* num_spurious += 1;*/
  74. }
  75. /*
  76.  * void amiga_init_IRQ(void)
  77.  *
  78.  * Parameters: None
  79.  *
  80.  * Returns: Nothing
  81.  *
  82.  * This function should be called during kernel startup to initialize
  83.  * the amiga IRQ handling routines.
  84.  */
  85. __init
  86. void amiga_init_IRQ(void)
  87. {
  88. int i;
  89. for (i = 0; i < AMI_IRQS; i++)
  90. ami_ablecount[i] = 0;
  91. /* turn off PCMCIA interrupts */
  92. if (AMIGAHW_PRESENT(PCMCIA))
  93. gayle.inten = GAYLE_IRQ_IDE;
  94. /* turn off all interrupts... */
  95. custom.intena = 0x7fff;
  96. custom.intreq = 0x7fff;
  97. #ifdef CONFIG_APUS
  98. /* Clear any inter-CPU interrupt requests. Circumvents bug in
  99.            Blizzard IPL emulation HW (or so it appears). */
  100. APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
  101. /* Init IPL emulation. */
  102. APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL);
  103. APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
  104. APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK);
  105. #endif
  106. /* ... and enable the master interrupt bit */
  107. custom.intena = IF_SETCLR | IF_INTEN;
  108. cia_init_IRQ(&ciaa_base);
  109. cia_init_IRQ(&ciab_base);
  110. }
  111. /*
  112.  * Enable/disable a particular machine specific interrupt source.
  113.  * Note that this may affect other interrupts in case of a shared interrupt.
  114.  * This function should only be called for a _very_ short time to change some
  115.  * internal data, that may not be changed by the interrupt at the same time.
  116.  * ami_(enable|disable)_irq calls may also be nested.
  117.  */
  118. void amiga_enable_irq(unsigned int irq)
  119. {
  120. if (irq >= AMI_IRQS) {
  121. printk("%s: Unknown IRQ %dn", __FUNCTION__, irq);
  122. return;
  123. }
  124. ami_ablecount[irq]--;
  125. if (ami_ablecount[irq]<0)
  126. ami_ablecount[irq]=0;
  127. else if (ami_ablecount[irq])
  128. return;
  129. /* No action for auto-vector interrupts */
  130. if (irq >= IRQ_AMIGA_AUTO){
  131. printk("%s: Trying to enable auto-vector IRQ %in",
  132.        __FUNCTION__, irq - IRQ_AMIGA_AUTO);
  133. return;
  134. }
  135. if (irq >= IRQ_AMIGA_CIAA) {
  136. cia_set_irq(irq, 0);
  137. cia_able_irq(irq, 1);
  138. return;
  139. }
  140. /* enable the interrupt */
  141. custom.intena = IF_SETCLR | ami_intena_vals[irq];
  142. }
  143. void amiga_disable_irq(unsigned int irq)
  144. {
  145. if (irq >= AMI_IRQS) {
  146. printk("%s: Unknown IRQ %dn", __FUNCTION__, irq);
  147. return;
  148. }
  149. if (ami_ablecount[irq]++)
  150. return;
  151. /* No action for auto-vector interrupts */
  152. if (irq >= IRQ_AMIGA_AUTO) {
  153. printk("%s: Trying to disable auto-vector IRQ %in",
  154.        __FUNCTION__, irq - IRQ_AMIGA_AUTO);
  155. return;
  156. }
  157. if (irq >= IRQ_AMIGA_CIAA) {
  158. cia_able_irq(irq, 0);
  159. return;
  160. }
  161. /* disable the interrupt */
  162. custom.intena = ami_intena_vals[irq];
  163. }
  164. inline void amiga_do_irq(int irq, struct pt_regs *fp)
  165. {
  166. irq_desc_t *desc = irq_desc + irq;
  167. struct irqaction *action = desc->action;
  168. kstat.irqs[0][irq]++;
  169. action->handler(irq, action->dev_id, fp);
  170. }
  171. void amiga_do_irq_list(int irq, struct pt_regs *fp)
  172. {
  173. irq_desc_t *desc = irq_desc + irq;
  174. struct irqaction *action;
  175. kstat.irqs[0][irq]++;
  176. custom.intreq = ami_intena_vals[irq];
  177. for (action = desc->action; action; action = action->next)
  178. action->handler(irq, action->dev_id, fp);
  179. }
  180. /*
  181.  * The builtin Amiga hardware interrupt handlers.
  182.  */
  183. static void ami_int1(int irq, void *dev_id, struct pt_regs *fp)
  184. {
  185. unsigned short ints = custom.intreqr & custom.intenar;
  186. /* if serial transmit buffer empty, interrupt */
  187. if (ints & IF_TBE) {
  188. custom.intreq = IF_TBE;
  189. amiga_do_irq(IRQ_AMIGA_TBE, fp);
  190. }
  191. /* if floppy disk transfer complete, interrupt */
  192. if (ints & IF_DSKBLK) {
  193. custom.intreq = IF_DSKBLK;
  194. amiga_do_irq(IRQ_AMIGA_DSKBLK, fp);
  195. }
  196. /* if software interrupt set, interrupt */
  197. if (ints & IF_SOFT) {
  198. custom.intreq = IF_SOFT;
  199. amiga_do_irq(IRQ_AMIGA_SOFT, fp);
  200. }
  201. }
  202. static void ami_int3(int irq, void *dev_id, struct pt_regs *fp)
  203. {
  204. unsigned short ints = custom.intreqr & custom.intenar;
  205. /* if a blitter interrupt */
  206. if (ints & IF_BLIT) {
  207. custom.intreq = IF_BLIT;
  208. amiga_do_irq(IRQ_AMIGA_BLIT, fp);
  209. }
  210. /* if a copper interrupt */
  211. if (ints & IF_COPER) {
  212. custom.intreq = IF_COPER;
  213. amiga_do_irq(IRQ_AMIGA_COPPER, fp);
  214. }
  215. /* if a vertical blank interrupt */
  216. if (ints & IF_VERTB)
  217. amiga_do_irq_list(IRQ_AMIGA_VERTB, fp);
  218. }
  219. static void ami_int4(int irq, void *dev_id, struct pt_regs *fp)
  220. {
  221. unsigned short ints = custom.intreqr & custom.intenar;
  222. /* if audio 0 interrupt */
  223. if (ints & IF_AUD0) {
  224. custom.intreq = IF_AUD0;
  225. amiga_do_irq(IRQ_AMIGA_AUD0, fp);
  226. }
  227. /* if audio 1 interrupt */
  228. if (ints & IF_AUD1) {
  229. custom.intreq = IF_AUD1;
  230. amiga_do_irq(IRQ_AMIGA_AUD1, fp);
  231. }
  232. /* if audio 2 interrupt */
  233. if (ints & IF_AUD2) {
  234. custom.intreq = IF_AUD2;
  235. amiga_do_irq(IRQ_AMIGA_AUD2, fp);
  236. }
  237. /* if audio 3 interrupt */
  238. if (ints & IF_AUD3) {
  239. custom.intreq = IF_AUD3;
  240. amiga_do_irq(IRQ_AMIGA_AUD3, fp);
  241. }
  242. }
  243. static void ami_int5(int irq, void *dev_id, struct pt_regs *fp)
  244. {
  245. unsigned short ints = custom.intreqr & custom.intenar;
  246. /* if serial receive buffer full interrupt */
  247. if (ints & IF_RBF) {
  248. /* acknowledge of IF_RBF must be done by the serial interrupt */
  249. amiga_do_irq(IRQ_AMIGA_RBF, fp);
  250. }
  251. /* if a disk sync interrupt */
  252. if (ints & IF_DSKSYN) {
  253. custom.intreq = IF_DSKSYN;
  254. amiga_do_irq(IRQ_AMIGA_DSKSYN, fp);
  255. }
  256. }
  257. static void ami_int7(int irq, void *dev_id, struct pt_regs *fp)
  258. {
  259. panic ("level 7 interrupt receivedn");
  260. }
  261. #ifdef CONFIG_APUS
  262. /* The PPC irq handling links all handlers requested on the same vector
  263.    and executes them in a loop. Having ami_badint at the end of the chain
  264.    is a bad idea. */
  265. struct irqaction amiga_sys_irqaction[AUTO_IRQS] = {
  266. { handler: ami_badint, name: "spurious int" },
  267. { handler: ami_int1, name: "int1 handler" },
  268. { 0, /* CIAA */ },
  269. { handler: ami_int3, name: "int3 handler" },
  270. { handler: ami_int4, name: "int4 handler" },
  271. { handler: ami_int5, name: "int5 handler" },
  272. { 0, /* CIAB */ },
  273. { handler: ami_int7, name: "int7 handler" },
  274. };
  275. #else
  276. void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
  277. ami_badint, ami_int1, ami_badint, ami_int3,
  278. ami_int4, ami_int5, ami_badint, ami_int7
  279. };
  280. #endif