1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * linux/arch/m68k/atari/stmda.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 1994 Roman Hodek
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
8*4882a593Smuzhiyun * License. See the file COPYING in the main directory of this archive
9*4882a593Smuzhiyun * for more details.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* This file contains some function for controlling the access to the */
14*4882a593Smuzhiyun /* ST-DMA chip that may be shared between devices. Currently we have: */
15*4882a593Smuzhiyun /* TT: Floppy and ACSI bus */
16*4882a593Smuzhiyun /* Falcon: Floppy and SCSI */
17*4882a593Smuzhiyun /* */
18*4882a593Smuzhiyun /* The controlling functions set up a wait queue for access to the */
19*4882a593Smuzhiyun /* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */
20*4882a593Smuzhiyun /* put onto a queue and waked up later if the owner calls */
21*4882a593Smuzhiyun /* stdma_release(). Additionally, the caller gives his interrupt */
22*4882a593Smuzhiyun /* service routine to stdma_lock(). */
23*4882a593Smuzhiyun /* */
24*4882a593Smuzhiyun /* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */
25*4882a593Smuzhiyun /* not the ST-DMA chip itself. So falhd.c needs not to lock the */
26*4882a593Smuzhiyun /* chip. The interrupt is routed to falhd.c if IDE is configured, the */
27*4882a593Smuzhiyun /* model is a Falcon and the interrupt was caused by the HD controller */
28*4882a593Smuzhiyun /* (can be determined by looking at its status register). */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include <linux/types.h>
32*4882a593Smuzhiyun #include <linux/kdev_t.h>
33*4882a593Smuzhiyun #include <linux/genhd.h>
34*4882a593Smuzhiyun #include <linux/sched.h>
35*4882a593Smuzhiyun #include <linux/init.h>
36*4882a593Smuzhiyun #include <linux/interrupt.h>
37*4882a593Smuzhiyun #include <linux/wait.h>
38*4882a593Smuzhiyun #include <linux/module.h>
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun #include <asm/atari_stdma.h>
41*4882a593Smuzhiyun #include <asm/atariints.h>
42*4882a593Smuzhiyun #include <asm/atarihw.h>
43*4882a593Smuzhiyun #include <asm/io.h>
44*4882a593Smuzhiyun #include <asm/irq.h>
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static int stdma_locked; /* the semaphore */
47*4882a593Smuzhiyun /* int func to be called */
48*4882a593Smuzhiyun static irq_handler_t stdma_isr;
49*4882a593Smuzhiyun static void *stdma_isr_data; /* data passed to isr */
50*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /***************************** Prototypes *****************************/
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static irqreturn_t stdma_int (int irq, void *dummy);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /************************* End of Prototypes **************************/
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /**
63*4882a593Smuzhiyun * stdma_try_lock - attempt to acquire ST DMA interrupt "lock"
64*4882a593Smuzhiyun * @handler: interrupt handler to use after acquisition
65*4882a593Smuzhiyun *
66*4882a593Smuzhiyun * Returns !0 if lock was acquired; otherwise 0.
67*4882a593Smuzhiyun */
68*4882a593Smuzhiyun
stdma_try_lock(irq_handler_t handler,void * data)69*4882a593Smuzhiyun int stdma_try_lock(irq_handler_t handler, void *data)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun unsigned long flags;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun local_irq_save(flags);
74*4882a593Smuzhiyun if (stdma_locked) {
75*4882a593Smuzhiyun local_irq_restore(flags);
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun stdma_locked = 1;
80*4882a593Smuzhiyun stdma_isr = handler;
81*4882a593Smuzhiyun stdma_isr_data = data;
82*4882a593Smuzhiyun local_irq_restore(flags);
83*4882a593Smuzhiyun return 1;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun EXPORT_SYMBOL(stdma_try_lock);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun * Function: void stdma_lock( isrfunc isr, void *data )
90*4882a593Smuzhiyun *
91*4882a593Smuzhiyun * Purpose: Tries to get a lock on the ST-DMA chip that is used by more
92*4882a593Smuzhiyun * then one device driver. Waits on stdma_wait until lock is free.
93*4882a593Smuzhiyun * stdma_lock() may not be called from an interrupt! You have to
94*4882a593Smuzhiyun * get the lock in your main routine and release it when your
95*4882a593Smuzhiyun * request is finished.
96*4882a593Smuzhiyun *
97*4882a593Smuzhiyun * Inputs: A interrupt function that is called until the lock is
98*4882a593Smuzhiyun * released.
99*4882a593Smuzhiyun *
100*4882a593Smuzhiyun * Returns: nothing
101*4882a593Smuzhiyun *
102*4882a593Smuzhiyun */
103*4882a593Smuzhiyun
stdma_lock(irq_handler_t handler,void * data)104*4882a593Smuzhiyun void stdma_lock(irq_handler_t handler, void *data)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun /* Since the DMA is used for file system purposes, we
107*4882a593Smuzhiyun have to sleep uninterruptible (there may be locked
108*4882a593Smuzhiyun buffers) */
109*4882a593Smuzhiyun wait_event(stdma_wait, stdma_try_lock(handler, data));
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun EXPORT_SYMBOL(stdma_lock);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /*
115*4882a593Smuzhiyun * Function: void stdma_release( void )
116*4882a593Smuzhiyun *
117*4882a593Smuzhiyun * Purpose: Releases the lock on the ST-DMA chip.
118*4882a593Smuzhiyun *
119*4882a593Smuzhiyun * Inputs: none
120*4882a593Smuzhiyun *
121*4882a593Smuzhiyun * Returns: nothing
122*4882a593Smuzhiyun *
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun
stdma_release(void)125*4882a593Smuzhiyun void stdma_release(void)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun unsigned long flags;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun local_irq_save(flags);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun stdma_locked = 0;
132*4882a593Smuzhiyun stdma_isr = NULL;
133*4882a593Smuzhiyun stdma_isr_data = NULL;
134*4882a593Smuzhiyun wake_up(&stdma_wait);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun local_irq_restore(flags);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun EXPORT_SYMBOL(stdma_release);
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /**
142*4882a593Smuzhiyun * stdma_is_locked_by - allow lock holder to check whether it needs to release.
143*4882a593Smuzhiyun * @handler: interrupt handler previously used to acquire lock.
144*4882a593Smuzhiyun *
145*4882a593Smuzhiyun * Returns !0 if locked for the given handler; 0 otherwise.
146*4882a593Smuzhiyun */
147*4882a593Smuzhiyun
stdma_is_locked_by(irq_handler_t handler)148*4882a593Smuzhiyun int stdma_is_locked_by(irq_handler_t handler)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun unsigned long flags;
151*4882a593Smuzhiyun int result;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun local_irq_save(flags);
154*4882a593Smuzhiyun result = stdma_locked && (stdma_isr == handler);
155*4882a593Smuzhiyun local_irq_restore(flags);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return result;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun EXPORT_SYMBOL(stdma_is_locked_by);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun /*
163*4882a593Smuzhiyun * Function: int stdma_islocked( void )
164*4882a593Smuzhiyun *
165*4882a593Smuzhiyun * Purpose: Check if the ST-DMA is currently locked.
166*4882a593Smuzhiyun * Note: Returned status is only valid if ints are disabled while calling and
167*4882a593Smuzhiyun * as long as they remain disabled.
168*4882a593Smuzhiyun * If called with ints enabled, status can change only from locked to
169*4882a593Smuzhiyun * unlocked, because ints may not lock the ST-DMA.
170*4882a593Smuzhiyun *
171*4882a593Smuzhiyun * Inputs: none
172*4882a593Smuzhiyun *
173*4882a593Smuzhiyun * Returns: != 0 if locked, 0 otherwise
174*4882a593Smuzhiyun *
175*4882a593Smuzhiyun */
176*4882a593Smuzhiyun
stdma_islocked(void)177*4882a593Smuzhiyun int stdma_islocked(void)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun return stdma_locked;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun EXPORT_SYMBOL(stdma_islocked);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /*
185*4882a593Smuzhiyun * Function: void stdma_init( void )
186*4882a593Smuzhiyun *
187*4882a593Smuzhiyun * Purpose: Initialize the ST-DMA chip access controlling.
188*4882a593Smuzhiyun * It sets up the interrupt and its service routine. The int is registered
189*4882a593Smuzhiyun * as slow int, client devices have to live with that (no problem
190*4882a593Smuzhiyun * currently).
191*4882a593Smuzhiyun *
192*4882a593Smuzhiyun * Inputs: none
193*4882a593Smuzhiyun *
194*4882a593Smuzhiyun * Return: nothing
195*4882a593Smuzhiyun *
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun
stdma_init(void)198*4882a593Smuzhiyun void __init stdma_init(void)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun stdma_isr = NULL;
201*4882a593Smuzhiyun if (request_irq(IRQ_MFP_FDC, stdma_int, IRQF_SHARED,
202*4882a593Smuzhiyun "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int))
203*4882a593Smuzhiyun pr_err("Couldn't register ST-DMA interrupt\n");
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /*
208*4882a593Smuzhiyun * Function: void stdma_int()
209*4882a593Smuzhiyun *
210*4882a593Smuzhiyun * Purpose: The interrupt routine for the ST-DMA. It calls the isr
211*4882a593Smuzhiyun * registered by stdma_lock().
212*4882a593Smuzhiyun *
213*4882a593Smuzhiyun */
214*4882a593Smuzhiyun
stdma_int(int irq,void * dummy)215*4882a593Smuzhiyun static irqreturn_t stdma_int(int irq, void *dummy)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun if (stdma_isr)
218*4882a593Smuzhiyun (*stdma_isr)(irq, stdma_isr_data);
219*4882a593Smuzhiyun return IRQ_HANDLED;
220*4882a593Smuzhiyun }
221