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