162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/arch/m68k/atari/stmda.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1994 Roman Hodek 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 862306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 962306a36Sopenharmony_ci * for more details. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* This file contains some function for controlling the access to the */ 1462306a36Sopenharmony_ci/* ST-DMA chip that may be shared between devices. Currently we have: */ 1562306a36Sopenharmony_ci/* TT: Floppy and ACSI bus */ 1662306a36Sopenharmony_ci/* Falcon: Floppy and SCSI */ 1762306a36Sopenharmony_ci/* */ 1862306a36Sopenharmony_ci/* The controlling functions set up a wait queue for access to the */ 1962306a36Sopenharmony_ci/* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */ 2062306a36Sopenharmony_ci/* put onto a queue and waked up later if the owner calls */ 2162306a36Sopenharmony_ci/* stdma_release(). Additionally, the caller gives his interrupt */ 2262306a36Sopenharmony_ci/* service routine to stdma_lock(). */ 2362306a36Sopenharmony_ci/* */ 2462306a36Sopenharmony_ci/* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */ 2562306a36Sopenharmony_ci/* not the ST-DMA chip itself. So falhd.c needs not to lock the */ 2662306a36Sopenharmony_ci/* chip. The interrupt is routed to falhd.c if IDE is configured, the */ 2762306a36Sopenharmony_ci/* model is a Falcon and the interrupt was caused by the HD controller */ 2862306a36Sopenharmony_ci/* (can be determined by looking at its status register). */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/types.h> 3262306a36Sopenharmony_ci#include <linux/kdev_t.h> 3362306a36Sopenharmony_ci#include <linux/sched.h> 3462306a36Sopenharmony_ci#include <linux/init.h> 3562306a36Sopenharmony_ci#include <linux/interrupt.h> 3662306a36Sopenharmony_ci#include <linux/wait.h> 3762306a36Sopenharmony_ci#include <linux/module.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <asm/atari_stdma.h> 4062306a36Sopenharmony_ci#include <asm/atariints.h> 4162306a36Sopenharmony_ci#include <asm/atarihw.h> 4262306a36Sopenharmony_ci#include <asm/io.h> 4362306a36Sopenharmony_ci#include <asm/irq.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic int stdma_locked; /* the semaphore */ 4662306a36Sopenharmony_ci /* int func to be called */ 4762306a36Sopenharmony_cistatic irq_handler_t stdma_isr; 4862306a36Sopenharmony_cistatic void *stdma_isr_data; /* data passed to isr */ 4962306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/***************************** Prototypes *****************************/ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic irqreturn_t stdma_int (int irq, void *dummy); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/************************* End of Prototypes **************************/ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/** 6262306a36Sopenharmony_ci * stdma_try_lock - attempt to acquire ST DMA interrupt "lock" 6362306a36Sopenharmony_ci * @handler: interrupt handler to use after acquisition 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * Returns !0 if lock was acquired; otherwise 0. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciint stdma_try_lock(irq_handler_t handler, void *data) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci unsigned long flags; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci local_irq_save(flags); 7362306a36Sopenharmony_ci if (stdma_locked) { 7462306a36Sopenharmony_ci local_irq_restore(flags); 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci stdma_locked = 1; 7962306a36Sopenharmony_ci stdma_isr = handler; 8062306a36Sopenharmony_ci stdma_isr_data = data; 8162306a36Sopenharmony_ci local_irq_restore(flags); 8262306a36Sopenharmony_ci return 1; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ciEXPORT_SYMBOL(stdma_try_lock); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* 8862306a36Sopenharmony_ci * Function: void stdma_lock( isrfunc isr, void *data ) 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * Purpose: Tries to get a lock on the ST-DMA chip that is used by more 9162306a36Sopenharmony_ci * then one device driver. Waits on stdma_wait until lock is free. 9262306a36Sopenharmony_ci * stdma_lock() may not be called from an interrupt! You have to 9362306a36Sopenharmony_ci * get the lock in your main routine and release it when your 9462306a36Sopenharmony_ci * request is finished. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * Inputs: A interrupt function that is called until the lock is 9762306a36Sopenharmony_ci * released. 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * Returns: nothing 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_civoid stdma_lock(irq_handler_t handler, void *data) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci /* Since the DMA is used for file system purposes, we 10662306a36Sopenharmony_ci have to sleep uninterruptible (there may be locked 10762306a36Sopenharmony_ci buffers) */ 10862306a36Sopenharmony_ci wait_event(stdma_wait, stdma_try_lock(handler, data)); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ciEXPORT_SYMBOL(stdma_lock); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * Function: void stdma_release( void ) 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * Purpose: Releases the lock on the ST-DMA chip. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * Inputs: none 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Returns: nothing 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_civoid stdma_release(void) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci unsigned long flags; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci local_irq_save(flags); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci stdma_locked = 0; 13162306a36Sopenharmony_ci stdma_isr = NULL; 13262306a36Sopenharmony_ci stdma_isr_data = NULL; 13362306a36Sopenharmony_ci wake_up(&stdma_wait); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci local_irq_restore(flags); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ciEXPORT_SYMBOL(stdma_release); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/** 14162306a36Sopenharmony_ci * stdma_is_locked_by - allow lock holder to check whether it needs to release. 14262306a36Sopenharmony_ci * @handler: interrupt handler previously used to acquire lock. 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * Returns !0 if locked for the given handler; 0 otherwise. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciint stdma_is_locked_by(irq_handler_t handler) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci unsigned long flags; 15062306a36Sopenharmony_ci int result; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci local_irq_save(flags); 15362306a36Sopenharmony_ci result = stdma_locked && (stdma_isr == handler); 15462306a36Sopenharmony_ci local_irq_restore(flags); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return result; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ciEXPORT_SYMBOL(stdma_is_locked_by); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* 16262306a36Sopenharmony_ci * Function: int stdma_islocked( void ) 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * Purpose: Check if the ST-DMA is currently locked. 16562306a36Sopenharmony_ci * Note: Returned status is only valid if ints are disabled while calling and 16662306a36Sopenharmony_ci * as long as they remain disabled. 16762306a36Sopenharmony_ci * If called with ints enabled, status can change only from locked to 16862306a36Sopenharmony_ci * unlocked, because ints may not lock the ST-DMA. 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * Inputs: none 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * Returns: != 0 if locked, 0 otherwise 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint stdma_islocked(void) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci return stdma_locked; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ciEXPORT_SYMBOL(stdma_islocked); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* 18462306a36Sopenharmony_ci * Function: void stdma_init( void ) 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * Purpose: Initialize the ST-DMA chip access controlling. 18762306a36Sopenharmony_ci * It sets up the interrupt and its service routine. The int is registered 18862306a36Sopenharmony_ci * as slow int, client devices have to live with that (no problem 18962306a36Sopenharmony_ci * currently). 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * Inputs: none 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * Return: nothing 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid __init stdma_init(void) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci stdma_isr = NULL; 20062306a36Sopenharmony_ci if (request_irq(IRQ_MFP_FDC, stdma_int, IRQF_SHARED, 20162306a36Sopenharmony_ci "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int)) 20262306a36Sopenharmony_ci pr_err("Couldn't register ST-DMA interrupt\n"); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * Function: void stdma_int() 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * Purpose: The interrupt routine for the ST-DMA. It calls the isr 21062306a36Sopenharmony_ci * registered by stdma_lock(). 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic irqreturn_t stdma_int(int irq, void *dummy) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci if (stdma_isr) 21762306a36Sopenharmony_ci (*stdma_isr)(irq, stdma_isr_data); 21862306a36Sopenharmony_ci return IRQ_HANDLED; 21962306a36Sopenharmony_ci} 220