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/genhd.h> 34#include <linux/sched.h> 35#include <linux/init.h> 36#include <linux/interrupt.h> 37#include <linux/wait.h> 38#include <linux/module.h> 39 40#include <asm/atari_stdma.h> 41#include <asm/atariints.h> 42#include <asm/atarihw.h> 43#include <asm/io.h> 44#include <asm/irq.h> 45 46static int stdma_locked; /* the semaphore */ 47 /* int func to be called */ 48static irq_handler_t stdma_isr; 49static void *stdma_isr_data; /* data passed to isr */ 50static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ 51 52 53 54 55/***************************** Prototypes *****************************/ 56 57static irqreturn_t stdma_int (int irq, void *dummy); 58 59/************************* End of Prototypes **************************/ 60 61 62/** 63 * stdma_try_lock - attempt to acquire ST DMA interrupt "lock" 64 * @handler: interrupt handler to use after acquisition 65 * 66 * Returns !0 if lock was acquired; otherwise 0. 67 */ 68 69int 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} 85EXPORT_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 104void 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} 111EXPORT_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 125void 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} 138EXPORT_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 148int 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} 159EXPORT_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 177int stdma_islocked(void) 178{ 179 return stdma_locked; 180} 181EXPORT_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 198void __init stdma_init(void) 199{ 200 stdma_isr = NULL; 201 if (request_irq(IRQ_MFP_FDC, stdma_int, IRQF_SHARED, 202 "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", 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 215static 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