18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/arch/m68k/atari/stmda.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1994 Roman Hodek 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 88c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 98c2ecf20Sopenharmony_ci * for more details. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* This file contains some function for controlling the access to the */ 148c2ecf20Sopenharmony_ci/* ST-DMA chip that may be shared between devices. Currently we have: */ 158c2ecf20Sopenharmony_ci/* TT: Floppy and ACSI bus */ 168c2ecf20Sopenharmony_ci/* Falcon: Floppy and SCSI */ 178c2ecf20Sopenharmony_ci/* */ 188c2ecf20Sopenharmony_ci/* The controlling functions set up a wait queue for access to the */ 198c2ecf20Sopenharmony_ci/* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */ 208c2ecf20Sopenharmony_ci/* put onto a queue and waked up later if the owner calls */ 218c2ecf20Sopenharmony_ci/* stdma_release(). Additionally, the caller gives his interrupt */ 228c2ecf20Sopenharmony_ci/* service routine to stdma_lock(). */ 238c2ecf20Sopenharmony_ci/* */ 248c2ecf20Sopenharmony_ci/* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */ 258c2ecf20Sopenharmony_ci/* not the ST-DMA chip itself. So falhd.c needs not to lock the */ 268c2ecf20Sopenharmony_ci/* chip. The interrupt is routed to falhd.c if IDE is configured, the */ 278c2ecf20Sopenharmony_ci/* model is a Falcon and the interrupt was caused by the HD controller */ 288c2ecf20Sopenharmony_ci/* (can be determined by looking at its status register). */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/types.h> 328c2ecf20Sopenharmony_ci#include <linux/kdev_t.h> 338c2ecf20Sopenharmony_ci#include <linux/genhd.h> 348c2ecf20Sopenharmony_ci#include <linux/sched.h> 358c2ecf20Sopenharmony_ci#include <linux/init.h> 368c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 378c2ecf20Sopenharmony_ci#include <linux/wait.h> 388c2ecf20Sopenharmony_ci#include <linux/module.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <asm/atari_stdma.h> 418c2ecf20Sopenharmony_ci#include <asm/atariints.h> 428c2ecf20Sopenharmony_ci#include <asm/atarihw.h> 438c2ecf20Sopenharmony_ci#include <asm/io.h> 448c2ecf20Sopenharmony_ci#include <asm/irq.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int stdma_locked; /* the semaphore */ 478c2ecf20Sopenharmony_ci /* int func to be called */ 488c2ecf20Sopenharmony_cistatic irq_handler_t stdma_isr; 498c2ecf20Sopenharmony_cistatic void *stdma_isr_data; /* data passed to isr */ 508c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/***************************** Prototypes *****************************/ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic irqreturn_t stdma_int (int irq, void *dummy); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/************************* End of Prototypes **************************/ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/** 638c2ecf20Sopenharmony_ci * stdma_try_lock - attempt to acquire ST DMA interrupt "lock" 648c2ecf20Sopenharmony_ci * @handler: interrupt handler to use after acquisition 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * Returns !0 if lock was acquired; otherwise 0. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciint stdma_try_lock(irq_handler_t handler, void *data) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci unsigned long flags; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci local_irq_save(flags); 748c2ecf20Sopenharmony_ci if (stdma_locked) { 758c2ecf20Sopenharmony_ci local_irq_restore(flags); 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci stdma_locked = 1; 808c2ecf20Sopenharmony_ci stdma_isr = handler; 818c2ecf20Sopenharmony_ci stdma_isr_data = data; 828c2ecf20Sopenharmony_ci local_irq_restore(flags); 838c2ecf20Sopenharmony_ci return 1; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(stdma_try_lock); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * Function: void stdma_lock( isrfunc isr, void *data ) 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * Purpose: Tries to get a lock on the ST-DMA chip that is used by more 928c2ecf20Sopenharmony_ci * then one device driver. Waits on stdma_wait until lock is free. 938c2ecf20Sopenharmony_ci * stdma_lock() may not be called from an interrupt! You have to 948c2ecf20Sopenharmony_ci * get the lock in your main routine and release it when your 958c2ecf20Sopenharmony_ci * request is finished. 968c2ecf20Sopenharmony_ci * 978c2ecf20Sopenharmony_ci * Inputs: A interrupt function that is called until the lock is 988c2ecf20Sopenharmony_ci * released. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Returns: nothing 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_civoid stdma_lock(irq_handler_t handler, void *data) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci /* Since the DMA is used for file system purposes, we 1078c2ecf20Sopenharmony_ci have to sleep uninterruptible (there may be locked 1088c2ecf20Sopenharmony_ci buffers) */ 1098c2ecf20Sopenharmony_ci wait_event(stdma_wait, stdma_try_lock(handler, data)); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(stdma_lock); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* 1158c2ecf20Sopenharmony_ci * Function: void stdma_release( void ) 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * Purpose: Releases the lock on the ST-DMA chip. 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Inputs: none 1208c2ecf20Sopenharmony_ci * 1218c2ecf20Sopenharmony_ci * Returns: nothing 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_civoid stdma_release(void) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci unsigned long flags; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci local_irq_save(flags); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci stdma_locked = 0; 1328c2ecf20Sopenharmony_ci stdma_isr = NULL; 1338c2ecf20Sopenharmony_ci stdma_isr_data = NULL; 1348c2ecf20Sopenharmony_ci wake_up(&stdma_wait); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci local_irq_restore(flags); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(stdma_release); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/** 1428c2ecf20Sopenharmony_ci * stdma_is_locked_by - allow lock holder to check whether it needs to release. 1438c2ecf20Sopenharmony_ci * @handler: interrupt handler previously used to acquire lock. 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Returns !0 if locked for the given handler; 0 otherwise. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ciint stdma_is_locked_by(irq_handler_t handler) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci unsigned long flags; 1518c2ecf20Sopenharmony_ci int result; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci local_irq_save(flags); 1548c2ecf20Sopenharmony_ci result = stdma_locked && (stdma_isr == handler); 1558c2ecf20Sopenharmony_ci local_irq_restore(flags); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return result; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(stdma_is_locked_by); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * Function: int stdma_islocked( void ) 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Purpose: Check if the ST-DMA is currently locked. 1668c2ecf20Sopenharmony_ci * Note: Returned status is only valid if ints are disabled while calling and 1678c2ecf20Sopenharmony_ci * as long as they remain disabled. 1688c2ecf20Sopenharmony_ci * If called with ints enabled, status can change only from locked to 1698c2ecf20Sopenharmony_ci * unlocked, because ints may not lock the ST-DMA. 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Inputs: none 1728c2ecf20Sopenharmony_ci * 1738c2ecf20Sopenharmony_ci * Returns: != 0 if locked, 0 otherwise 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciint stdma_islocked(void) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci return stdma_locked; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(stdma_islocked); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * Function: void stdma_init( void ) 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Purpose: Initialize the ST-DMA chip access controlling. 1888c2ecf20Sopenharmony_ci * It sets up the interrupt and its service routine. The int is registered 1898c2ecf20Sopenharmony_ci * as slow int, client devices have to live with that (no problem 1908c2ecf20Sopenharmony_ci * currently). 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Inputs: none 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Return: nothing 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_civoid __init stdma_init(void) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci stdma_isr = NULL; 2018c2ecf20Sopenharmony_ci if (request_irq(IRQ_MFP_FDC, stdma_int, IRQF_SHARED, 2028c2ecf20Sopenharmony_ci "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int)) 2038c2ecf20Sopenharmony_ci pr_err("Couldn't register ST-DMA interrupt\n"); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * Function: void stdma_int() 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * Purpose: The interrupt routine for the ST-DMA. It calls the isr 2118c2ecf20Sopenharmony_ci * registered by stdma_lock(). 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic irqreturn_t stdma_int(int irq, void *dummy) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci if (stdma_isr) 2188c2ecf20Sopenharmony_ci (*stdma_isr)(irq, stdma_isr_data); 2198c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2208c2ecf20Sopenharmony_ci} 221