[comp.sys.atari.st] ST acia interrupt handler

mike@pixar.UUCP (Mike Russell) (10/26/88)

I'm posting the following code in response to recent questions re
the ST ACIA registers.  This code includes register bit definitions
plus a set of functions for managing ACIA interrupts.

Mike Russell ucbvax!pixar!mike	Trust in Allah, but
				tie your camel first.


---------------------- include file for Atari ST/Mega ACIA
/* aciareg.h - definitions for Atari ST serial communications chip */

#define ACIA_MIDI (aciareg *)0xfffffc04
typedef struct aciareg {
	char csr;
	char filler;
	char data;
} aciareg;

/* control bits, write only */
#define C_RESET		0x3		/* master reset */
#define C_DIV1		0x0		/* divide clock by 1 */
#define C_DIV16		0x1		/* divide clock by 16, normal for MIDI */
#define C_DIV64		0x2		/* divide clock by 64 */

#define C_7EVEN2	0x00	/* seven bits, even parity, 2 stop bits */
#define C_7ODD2	0x04	/* seven bits, odd  parity, 2 stop bits */
#define C_7EVEN1	0x08	/* seven bits, even parity, 1 stop bit  */
#define C_7ODD1	0x0c	/* seven bits, even parity, 1 stop bit  */

#define C_8NONE2	0x10	/* eight bits, no   parity, 2 stop bits */
#define C_8NONE1	0x14	/* eight bits, no   parity, 1 stop bits */
#define C_8EVEN1	0x18	/* eight bits, even parity, 1 stop bit  */
#define C_8ODD1	0x1c		/* eight bits, odd  parity, 1 stop bit  */

#define	C_NO_RTS	0x40	/* disable RTS */
#define C_TIENA	0x20		/* enable transmit interrupts */
							/* note: CTL_NO_RTS|CTL_TIENA sends a break */
#define C_RIENA	0x80		/* enable reveive interrupts */

#define INIT_MIDI	(C_RIENA|C_8NONE1|C_DIV16)	/* init MIDI */
#define INIT_KBD	(C_RIENA|C_8NONE1|C_DIV64)	/* init keyboard */

/* status bits, read only */
#define S_RDATA		0x01	/* received data is present */
#define S_XEMPTY	0x02	/* transmitter is ready */
#define S_NOCARR	0x04	/* no carrier */
#define S_CTS		0x08	/* no clear to send signal */
#define S_FE		0x10	/* framing error */
#define S_OVRN		0x20	/* reveive overrun */
#define S_PE		0x40	/* parity error */
#define S_IRQ		0x80	/* interrupt request */

#define S_ERROR		(S_FE|S_OVRN|S_PE)	/* a receive error has occurred */
---------------------- interrupt handler for Atari ST/Mega MIDI
#include <osbind.h>
#include <aciareg.h>

typedef int (func)();

static func *imidiin, *imidiout;	/* i/o interrupt handlers */
static func *omidisys;				/* original midi vector */

static nullfunc() {}

midisys()	/* MIDI interrupt handler */
{
	register aciareg *acia = ACIA_MIDI;
	char c;
	static xmitloop;	/* transmitter interrupt loop detector */
#define XMITMAX 1000
	
	if(acia->csr&S_RDATA && (c = acia->data) != (char)0xfe {
		(*imidiin)(c);
	}
	if(acia->csr&S_XEMPTY) {
		if(imidiout) {
			(*imidiout)();
			
			/* guard against transmitter interrupt loop */
			if(acia->csr&S_XEMPTY) {
				if(++xmitloop>XMITMAX)
					acia->csr = INIT_MIDI;
				} else {
					xmitloop = 0;
				}
		} else {
			acia->csr = INIT_MIDI;
		}
	}
}

func *
MidiISubr() { return imidiin; }	/* get current input interrupt func */

func *
MidiOSubr() { return imidiout; } /* get current output interrupt func */

MidiSys(isubr, osubr)
func *isubr;	/* MIDI input interrupt handler or zero */
func *osubr;	/* MIDI output interrupt handler or zero */
/*
** Set up the MIDI ACIA to call C function isubr for input interrupts
** and osubr() for output interrupts.  May be called while MIDI is
** active (but be ready for lost characters).  Call with both functions
** set to zero to reset the first existing MIDI vector.
*/
{
	register aciareg *acia = ACIA_MIDI;
	register kbdvecs *kv = Kbdvbase();
	long osp;
	
	imidiin =  isubr?isubr:nullfunc;
	imidiout = osubr?osubr:nullfunc;
		
	if(isubr || osubr) {
		if(!omidisys)
			omidisys = kv->midisys;	/* save the original vector */
		kv->midisys = midisys;		/* replace it with our own */
	} else {
		if(omidisys)
			kv->midisys = omidisys;	/* restore the original vector */
	}
	
	osp = Super(0L);
	
	/* if output function specified, enable transmit interrupts */
	if(osubr)
		acia->csr = INIT_MIDI|C_TIENA;
	else
		acia->csr = INIT_MIDI;
	Super(osp);
}
#ifdef MAIN
#include <stdio.h>
int booby;
ifunc()
{
	booby++;
}

main()
{
	int obooby = 0;
		
	setbuf(stdout, NULL);
	MidiSys(ifunc, 0L);
	while(booby < 30) {
		if(obooby != booby)
			printf("%d\n", obooby = booby);
	}
	MidiSys(0L, 0L);
}
#endif MAIN
-- 
Mike Russell ucbvax!pixar!mike	Trust in Allah, but
				tie your camel first.