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