/*
	Midilowlevel.c - CAMD Mididriver for Normal rs-323 midi-interface,
	the Triple Play Plus rs-323 midi-interface, and the Quadra Play rs-323
	midi-interface. Written by Kjetil S. Matheussen.

	Updated: 12.4.2k. Changes: Used as a part of the CAMD TPP/QP driver,
	                           and major changes had to be done.


Copyright 1999-2000 Kjetil S. Matheussen

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/


#define fastDisable() dff000->intena=0x4000 /* ; SysBase->IDNestCnt++ */
#define fastEnable()  /* SysBase->IDNestCnt--; */ dff000->intena=0xc000

#include <dos.h>
#include <exec/types.h>
#include <exec/execbase.h>
#include <hardware/custom.h>
#include <hardware/cia.h>
#include <hardware/intbits.h>

extern struct Task *waitforporttask;
extern ULONG waitforportsig;

extern void __asm mySignal(
	register __a6 APTR execbase,
	register __a1 struct Task *tsk,
	register __d0 ULONG sig
);

extern BOOL __asm sendmidibyte(
	register __a0 APTR code,
	register __a3 APTR custom,
	register __a2 LONG data
);

struct CodeandDataelements{
	LONG data;
	APTR code;
};

struct CodeandData{
	struct CodeandDataelements cade[4];
};

/*
	tbeinterrupt - TBE interrupt code.
   There is a bit of lowlevel programming here,
	refer to the amiga hardware-manual for more info.
*/

__far extern struct CIA ciab;

BOOL Xmit[4]={FALSE};
UBYTE currentport=3;
UBYTE changeport=0;
BOOL waitsending=FALSE;
BOOL finishedport=TRUE;
extern void __asm putbyte(register __d1 long ai);

#define checkTSRE() (dff000->serdatr&(1<<12))

#define changeportproc(aiaiai) \
			if(checkTSRE()){ \
				ciab.ciapra^=(currentport^aiaiai)<<6; \
				currentport=aiaiai; \
			}else{ \
				changeport=currentport^aiaiai; \
				currentport=aiaiai; \
				waitsending=TRUE; \
				fastEnable(); \
				mySignal(SysBase,waitforporttask,(ULONG)(1<<waitforportsig)); \
				return; \
			}


void __saveds __asm tbeinterrupt(
	register __a0 struct Custom *dff000,
	register __a1 struct CodeandData *codeanddata,
	register __a6 struct ExecBase *SysBase
){

	fastDisable();

	dff000->intreq=1;		/*Clear intreq tbe bit. Tell that now I've been here. */

	if(waitsending){
		fastEnable();
		return;
	}

	if(changeport!=0){
		ciab.ciapra^=changeport<<6;
		changeport=0;
	}

	if(Xmit[currentport]){
		Xmit[currentport]=sendmidibyte(codeanddata->cade[currentport].code,dff000,codeanddata->cade[currentport].data);
	}else{
		if(Xmit[3]==TRUE){
			changeportproc(3);
			Xmit[3]=sendmidibyte(codeanddata->cade[3].code,dff000,codeanddata->cade[3].data);
		}else{
		if(Xmit[2]==TRUE){
			changeportproc(2);
			Xmit[2]=sendmidibyte(codeanddata->cade[2].code,dff000,codeanddata->cade[2].data);
		}else{
		if(Xmit[1]==TRUE){
			changeportproc(1);
			Xmit[1]=sendmidibyte(codeanddata->cade[1].code,dff000,codeanddata->cade[1].data);
		}else{
		if(Xmit[0]==TRUE){
			changeportproc(0);
			Xmit[0]=sendmidibyte(codeanddata->cade[0].code,dff000,codeanddata->cade[0].data);
		}}}}
	}

	fastEnable();
}

__far extern struct Custom custom;

#define causeTBE() if(custom.serdatr&1L<<13) custom.intreq=0x8001;

void __saveds ActivateXmit3(void){
	Xmit[3]=TRUE;
	causeTBE();
}
void __saveds ActivateXmit2(void){
	Xmit[2]=TRUE;
	causeTBE();
}
void __saveds ActivateXmit1(void){
	Xmit[1]=TRUE;
	causeTBE();
}
void __saveds ActivateXmit0(void){
	Xmit[0]=TRUE;
	causeTBE();
}





