xref: /OK3568_Linux_fs/kernel/arch/m68k/atari/stdma.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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