/****************************************************************************
lc -b0 -v -csu -r -j73 AXAux-Handler.c
blink AXAux-Handler.o TO AXsh:bin/AXAux-Handler LIBRARY lib:lc.lib lib:amiga.lib
copy AXAux-Handler.c AXsh:usr/src/
quit
 *
 *  AXAUX:serial.device/0/raw[con]/exclusive[shared]/7wire[noflow]/speed<speed>
 *
 *  Aux-Handler Ver. 1.1  20-Jul-1991
 *				Ver. 1.15  9-Jan-1992
 *				Ver. 1.20 14-Apr-1992
 *				Ver. 1.25 11-Oct-1992
 *				Ver. 1.26 30-Jan-1993
 *
 * 	Pasi Ojala
 * 	Kostulantie 67/50
 *  39230 Osara
 *
 *	Aux Driver V1.0 (c)CopyRight 1987, Steve Drew.
 *
 *	Steve Drew
 *	52-Castledale Cres. N.E.
 *	Calgary, Ab. Canada.
 ***************************************************************************/

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/devices.h>
#include <exec/io.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <devices/console.h>
#include <libraries/filehandler.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <graphics/gfxbase.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>
#include <stdlib.h>

char *vers="\0$VER: AXAUX-Handler 1.26 (30-Jan-93)\n";

#undef  BADDR
#define BADDR(x)   ((APTR)((long)x << 2))
/*	these are defined in dosextens..
#define ACTION_WAIT_CHAR	20
#define ACTION_WRITE		'W'
#define ACTION_READ			'R'
#define ACTION_FINDINPUT	1005L
#define ACTION_FINDOUTPUT	1006L
#define ACTION_END			1007L
#define ACTION_SCREEN_MODE	994L	*/

#define ACTION_QUERY		64	/* our own action */

#define MODE_CONSOLE		0	/* normal buffered console mode */
#define MODE_RAW			1	/* raw mode, no line editing nor echo */
#define MODE_NOCRLF			2	/* CR not added to LF, all codes will be sent (0)*/

#define DOS_FALSE			0L
#define DOS_TRUE			-1L

#define AUX_ECHO			1	/* echo characters */
#define AUX_CRLF			2	/* append LF to CR and vice versa (output) */

#define AUX_TYPEAHEAD_FULL	32	/* aux-buffer is full, CMD_READ NOT active */

#define AUXBUFSIZE			8192
#define MAXLINESIZE			AUXBUFSIZE-2	/* save two for \n'\0'  */
#define OUTBUFSIZE			1024
#define DEVICENAMELEN		32


#define MYPORT_SIG	(1L<<myport->mp_SigBit)		/* signal bit for requests */
#define READSER_SIG	(1L<<ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit)
#define TIMER_SIG	(1L<<Timer_Port->mp_SigBit)

/* Prototypes */

void returnpkt(struct DosPacket*,struct Process*,ULONG,ULONG);	/* sends back the packet */
struct DosPacket *taskwait();

void close_timer(void);
void close_ser(void);
int	 open_stuff(void);
void puts_ser(UBYTE *buf,int len);
void write_ser(UBYTE *,int);
int	 buf_ser(UBYTE *frombuf,int size);
int  query_ser(void);
void get_ser(UBYTE *destbuf,int size);
void set_read(void);
void chk_file(char *);

void returnpkt(struct DosPacket *packet,struct Process *myproc,ULONG res1,ULONG res2);
struct DosPacket *taskwait(struct Process *myproc);
int tolower(int);

/* Globals */

struct	IOExtSer	*ReadSER;
struct	IOExtSer	*WriteSER;
struct	IOExtSer	*QuerySER;
struct  timerequest	*Timer;
struct	MsgPort		*Timer_Port;
struct  Task		*reader;
VOID 				*SysBase;
int					aux_stat,aux_avail,in_len;
UBYTE				in_c,serflags,breakallowed,Mode;
char				checkcd;
long				unitnum,SerialStatus,SerialSpeed;
char				device[DEVICENAMELEN],
					outbuf[OUTBUFSIZE+1],
					*auxbuf;	/* Our type ahead buffer */


void __saveds handler(void);
void __saveds handler()	/* this is kinda main() */
{
	struct Process		*myproc;	/* my process */
	struct DosPacket	*mypkt,*rdpkt=NULL,*waitpkt=NULL;
						/* pointers to the dos packets */
	struct DeviceNode	*mynode; 	/* our device node (parmpkt Arg3) */
	struct FileHandle	*fh;	 	/* a pointer to our file handle	  */
	struct MsgPort		*myport;
	BOOL		  		run=TRUE;	/* handler main loop flag */
	UBYTE				*ptr;		/* ptr for name translation */
	char				*s;			/* ptr to name for open */
	int					i,tmp,aux_open=0;	/* aux open count */
	long				signals;			/* signals that occurred */
	char				name[200];	/* filename passed to */

	/* Initializing the handler */

#ifndef LATTICE
    mygeta4();
#endif

	SysBase=*(void **)4;
	myproc = (struct Process *)FindTask(0L);
	mypkt  = taskwait(myproc);	  /* Wait for the startup message */

	/* We don't need the name or extra info passed in Arg1/2 */

	mynode = (struct DeviceNode *)BADDR(mypkt->dp_Arg3);
	mynode->dn_Task = &myproc->pr_MsgPort;
	myport = &myproc->pr_MsgPort;
	returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);

	auxbuf=0L;
	SerialStatus=breakallowed=in_len=aux_avail=0;
	aux_stat=AUX_CRLF;
	Mode=MODE_RAW;
	reader = (struct Task *)NULL;
	checkcd=0;

	/* done initial stuff, now for some work */
	while(run)
	{
		if(aux_open)	/* then wait for read char or new action */
		{
			signals=Wait(MYPORT_SIG | READSER_SIG | TIMER_SIG);
			if((signals & TIMER_SIG) && CheckIO((struct IORequest *)Timer))
			{
				WaitIO((struct IORequest *)Timer);
				if(waitpkt)
				{
					(void)query_ser();
					if(checkcd && (SerialStatus & (1L<<5)))	/* CD dropped */
					{
						Signal(waitpkt->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
						returnpkt(waitpkt,myproc,DOS_TRUE,in_len);
						/* EOF can be read :-) */
					}
					else
					if(in_len)	/* TODO: handle chars in serial buffer */
					{
						returnpkt(waitpkt,myproc,DOS_TRUE,in_len);
					}
					else
					{
						returnpkt(waitpkt,myproc,DOS_FALSE,waitpkt->dp_Res2);
					}
					waitpkt=NULL;
				}
			}
			if((signals & READSER_SIG) && CheckIO((struct IORequest *)ReadSER))
			{
				WaitIO((struct IORequest *)ReadSER);	/* fine, got a char */
				if(buf_ser(&in_c,1))
				{
					tmp=query_ser();
					if(tmp && AUXBUFSIZE-in_len-2>10)
					{
						if(tmp>AUXBUFSIZE-in_len-9)
							tmp=AUXBUFSIZE-in_len-10;	/* hysteresis */
						get_ser(outbuf,tmp);
						buf_ser(outbuf,tmp);
					}
					set_read();	/* because buffer is not full, start another read */
				}
				if(waitpkt)
				{
					AbortIO((struct IORequest *)Timer);
					WaitIO((struct IORequest *)Timer);
					Wait(TIMER_SIG);
					if(checkcd && (SerialStatus & (1L<<5)))	/* CD dropped */
					{
						Signal(waitpkt->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
						returnpkt(waitpkt,myproc,DOS_TRUE,in_len);
						/* EOF can be read :-) */
					}
					else
					{
						returnpkt(waitpkt,myproc,DOS_TRUE,in_len);
					}
					waitpkt=NULL;
				}
				if(rdpkt)
				{
					if(checkcd && (SerialStatus & (1L<<5)))	/* CD dropped */
					{
						Signal(rdpkt->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
						returnpkt(rdpkt,myproc,DOS_FALSE,rdpkt->dp_Res2);
						/* return EOF */
						rdpkt=NULL;
					}
					else
					{
						if(Mode==MODE_RAW)
						{
							if(in_len)
							{
								if(in_len<=rdpkt->dp_Arg3)
								{
									movmem(auxbuf,(UBYTE *)rdpkt->dp_Arg2,in_len);
									i=in_len;
									aux_avail=in_len=0;
								}
								else
								{
									i=rdpkt->dp_Arg3;
									movmem(auxbuf,(UBYTE *)rdpkt->dp_Arg2,i);

									in_len-=i;
									movmem(auxbuf+i,auxbuf,in_len);
									aux_avail=tmp=0;
									while(tmp<in_len)
										if(auxbuf[tmp++]=='\n')
											aux_avail++;
								}
								if((aux_stat & AUX_TYPEAHEAD_FULL) && in_len<MAXLINESIZE-1)
								{
									aux_stat &= ~AUX_TYPEAHEAD_FULL;
									set_read();	/* start waiting for reads again */
								}
								returnpkt(rdpkt,myproc,(long)i,rdpkt->dp_Res2);
								rdpkt=NULL;
							}
						}
						else
						{
							if(aux_avail)
							{
								aux_avail--;
								i=0;
								ptr=(UBYTE *)rdpkt->dp_Arg2;
								while(i<rdpkt->dp_Arg3 && i<in_len)
								{
									if((ptr[i]=auxbuf[i])=='\n')
									{
										i++;
										break;
									}
									i++;
								}

								in_len-=i;
								movmem(auxbuf+i,auxbuf,in_len);

					 			if(ptr[i-1]!='\n')
									aux_avail++;

								if((aux_stat & AUX_TYPEAHEAD_FULL) && in_len<MAXLINESIZE-1)
								{
									aux_stat &= ~AUX_TYPEAHEAD_FULL;
									set_read();	/* start waiting for reads again */
								}
								returnpkt(rdpkt,myproc,(long)i,rdpkt->dp_Res2);
								rdpkt=NULL;
							}
						}
					}
				}
			}
			if(signals & MYPORT_SIG)
			{
				mypkt=taskwait(myproc);		/* somebody wanting to talk to us ? */
			}
			else
				continue;					/* no new dospackets - back to the beginning */
		}
		else
			mypkt=taskwait(myproc);		/* otherwise we just sit here and wait for someone to need us */

		switch(mypkt->dp_Type)				/* find what action to perform */
		{
		case ACTION_FINDINPUT:
			/* Have I already got someone reading and it is not 'reopen'.. */

			if(reader && (*((UBYTE *)BADDR(mypkt->dp_Arg3)+1)!='*'))
			{
				returnpkt(mypkt,myproc,DOS_FALSE,ERROR_OBJECT_IN_USE);
				break;
			}
			breakallowed=0;					/* fall through */
		case ACTION_FINDOUTPUT:
			/*	Multiple writers are allowed. */

			/* get file name and Upper case it */
			ptr=(UBYTE *)BADDR(mypkt->dp_Arg3);
			movmem(ptr+1,name,*ptr);
			name[*ptr]='\0';
			for(s=name;*s;s++)
				*s=tolower(*s);

			s=name;
			if(strcmp(name,"*"))
			{
				while(*s!=':' && *s)
					s++;		/* skip the handler name  */
				if(*s!=':')		/* weird, no handler name */
				{
					returnpkt(mypkt,myproc,DOS_FALSE,ERROR_OBJECT_IN_USE);
					break;
				}
				else
					s++;

				if(!strncmp(s,"break",5))	/* trying to send a break to the reader ? */
				{
					if(reader)
					{
						Signal(reader,SIGBREAKF_CTRL_C);
						Signal(reader,SIGBREAKF_CTRL_D);
					}
					returnpkt(mypkt,myproc,DOS_FALSE,ERROR_OBJECT_IN_USE);
					break;
				}

				if(!aux_open)  /* first time here we open the devices */
				{
					chk_file(s);	/* check parameters */
					if(!(aux_open=open_stuff()))
					{
						returnpkt(mypkt,myproc,DOS_FALSE,ERROR_OBJECT_IN_USE);
						break;
					}
				}
				else
					aux_open++;
			}
			else
			{	/* the same channel */
				if(!aux_open)
				{
					returnpkt(mypkt,myproc,DOS_FALSE,ERROR_OBJECT_IN_USE);
					break;
				}
				aux_open++;
			}

			fh = (struct FileHandle *)BADDR(mypkt->dp_Arg1);
			fh->fh_Arg1=DOS_TRUE;
			fh->fh_Port=(struct MsgPort *)DOS_TRUE;
			if(!reader && (mypkt->dp_Type==ACTION_FINDINPUT))
			{	struct MsgPort *port;

				port=mypkt->dp_Port;
				reader=port->mp_SigTask;
				fh->fh_Arg1=(long)port->mp_SigTask;
			}
			returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
			break;

		case ACTION_READ:
			rdpkt=mypkt;
			(void)query_ser();
			if(checkcd && (SerialStatus & (1L<<5)))	/* CD dropped */
			{
				Signal(rdpkt->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
				returnpkt(rdpkt,myproc,0,rdpkt->dp_Res2);	/* return EOF */
				rdpkt=NULL;
			}
			else
			{
				if(Mode==MODE_RAW)
				{
					if(in_len)
					{
						if(in_len<=rdpkt->dp_Arg3)
						{
							movmem(auxbuf,(UBYTE *)rdpkt->dp_Arg2,in_len);
							i=in_len;
							aux_avail=in_len=0;
						}
						else
						{
							i=rdpkt->dp_Arg3;
							movmem(auxbuf,(UBYTE *)rdpkt->dp_Arg2,i);

							in_len-=i;
							movmem(auxbuf+i,auxbuf,in_len);
							aux_avail=tmp=0;
							while(tmp<in_len)
								if(auxbuf[tmp++]=='\n')
									aux_avail++;
						}
						if((aux_stat & AUX_TYPEAHEAD_FULL) && in_len<MAXLINESIZE-1)
						{
							aux_stat &= ~AUX_TYPEAHEAD_FULL;
							set_read();	/* start waiting for reads again */
						}
						returnpkt(rdpkt,myproc,(long)i,rdpkt->dp_Res2);
						rdpkt=NULL;
					}
				}
				else
				{
					if(aux_avail)
					{
						aux_avail--;
						i=0;
						ptr=(UBYTE *)rdpkt->dp_Arg2;
						while(i<rdpkt->dp_Arg3 && i<in_len)
						{
							if((ptr[i]=auxbuf[i])=='\n')
							{
								i++;
								break;
							}
							i++;
						}

						in_len-=i;
						movmem(auxbuf+i,auxbuf,in_len);

			 			if(ptr[i]!='\n')
							aux_avail++;

						if((aux_stat & AUX_TYPEAHEAD_FULL) && in_len<MAXLINESIZE-1)
						{
							aux_stat &= ~AUX_TYPEAHEAD_FULL;
							set_read();	/* start waiting for reads again */
						}
						returnpkt(rdpkt,myproc,(long)i,rdpkt->dp_Res2);
						rdpkt=NULL;
						break;
					}
				}
			}
			break;

		case ACTION_WRITE:
			write_ser((char *)mypkt->dp_Arg2,(int)mypkt->dp_Arg3);

			/* tell 'em we wrote them all */
			returnpkt(mypkt,myproc,mypkt->dp_Arg3,mypkt->dp_Res2);
			break;

		case ACTION_WAIT_CHAR:		/* just queue up to wait for data */
			waitpkt=mypkt;

			(void)query_ser();
			if(checkcd && (SerialStatus & (1L<<5)))	/* CD dropped */
			{
				Signal(waitpkt->dp_Port->mp_SigTask,SIGBREAKF_CTRL_C);
				returnpkt(waitpkt,myproc,DOS_TRUE,in_len);
				/* EOF can be read :-) */
				waitpkt=NULL;
				break;
			}

			if(in_len)	/* if we have something, reply immediately */
			{
				returnpkt(waitpkt,myproc,DOS_TRUE,in_len);
				waitpkt=NULL;
				break;
			}
			if(!waitpkt->dp_Arg1)	/* if there is no wait, reply immediately */
			{
				returnpkt(waitpkt,myproc,DOS_FALSE,waitpkt->dp_Res2);
				waitpkt=NULL;
				break;
			}

			Timer->tr_time.tv_secs =0L;
			Timer->tr_time.tv_micro=waitpkt->dp_Arg1;
			SendIO((struct IORequest *)Timer);
			break;

		case ACTION_SCREEN_MODE:
			breakallowed=TRUE;		/* Break (^c or ^d) is allowed only after setmode */
			aux_stat |= AUX_ECHO;
			Mode=MODE_CONSOLE;
			if(mypkt->dp_Arg1==-1)	/* -1 means 'normal' Raw mode */
			{
				Mode=MODE_RAW;
				aux_stat |=  AUX_CRLF;
				aux_stat &= ~AUX_ECHO;
			}
			else
			{
				if(mypkt->dp_Arg1 & MODE_RAW)	/* raw means RAW and NOECHO */
				{
					aux_stat &= ~AUX_ECHO;
					Mode=MODE_RAW;
				}
				if(mypkt->dp_Arg1 & MODE_NOCRLF)	/* NOCRLF possible in console mode too */
				{
					aux_stat &= ~AUX_CRLF;
				}
				else
				{
					aux_stat |= AUX_CRLF;
				}
			}
			returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
			break;

		case ACTION_QUERY:
			(void)query_ser();
			returnpkt(mypkt,myproc,DOS_TRUE,SerialStatus);
			break;

		case ACTION_END:
			if(--aux_open==0)
			{
				run=FALSE;
				close_timer();
				if(!(aux_stat & AUX_TYPEAHEAD_FULL))
				{	AbortIO((struct IORequest *)ReadSER);
					WaitIO((struct IORequest *)ReadSER);
				}
				close_ser();
				reader=(struct Task *)NULL;
			}
  			if(mypkt->dp_Arg1==(long)reader)
				reader=(struct Task *)NULL;
			returnpkt(mypkt,myproc,DOS_TRUE,mypkt->dp_Res2);
			break;

		case ACTION_DISK_INFO:
		default:
			returnpkt(mypkt,myproc,DOS_FALSE,ERROR_ACTION_NOT_KNOWN);
  			break;
		}
	}
	mynode->dn_Task=FALSE;
}


/*  Start an asynchronous Read request */
void set_read()
{
	ReadSER->IOSer.io_Command=CMD_READ;
	ReadSER->IOSer.io_Length =1L;
	ReadSER->IOSer.io_Data	 =(APTR)&in_c;
	SendIO((struct IORequest *)ReadSER);
}

int query_ser()	/* we use a dedicated IORequest */
{
	QuerySER->IOSer.io_Command=SDCMD_QUERY;
	DoIO((struct IORequest *)QuerySER);
	SerialStatus=QuerySER->io_Status;
	return (int)QuerySER->IOSer.io_Actual;
}

void get_ser(UBYTE *destbuf,int size)
{
	ReadSER->IOSer.io_Command=CMD_READ;
	ReadSER->IOSer.io_Data	 =(APTR)destbuf;
	ReadSER->IOSer.io_Length =size;
	DoIO((struct IORequest *)ReadSER);
}


int buf_ser(UBYTE *s,int num)
{	UBYTE c;
	int i;

	if(Mode==MODE_RAW)
	{
		/* Copy the characters */
		movmem(s,auxbuf+in_len,num);
		in_len+=num;

		/* Check if any breaks or LF's were sent */
		if(reader && breakallowed)
		{
			for(i=0;i<num;i++)
			{
				c=s[i];
				if(c==0x03)
				{	/* ^C typed so immediately send the signal (if it is allowed) */
					Signal(reader,SIGBREAKF_CTRL_C);
					break;
				}
				else
				if(c==0x04)
				{	/* ^D typed so immediately send the signal (if it is allowed) */
					Signal(reader,SIGBREAKF_CTRL_D);
					break;
				}
				else
				if(c==0x0a)
					aux_avail++;  /* always done when CR received */
			}
		}
	}
	else
	{
		for(i=0;i<num;i++)
		{
			c=s[i];
			switch(c)
			{
			case 0x03:
				c=0;
				if(reader && breakallowed)
					Signal(reader,SIGBREAKF_CTRL_C);
				break;
			case 4:
				c=0;
				if(reader && breakallowed)
					Signal(reader,SIGBREAKF_CTRL_D);
				break;
			case 28:		/* ^\ so wipe out line and force EOF	  */
				in_len=c=0;
				++aux_avail;
				break;
			case 13:		/* CR convert to LF if CRLF turned on	  */
				if(aux_stat & AUX_CRLF)
					c=0x0a;
				break;
			case 10:		/* ignore these */
				if(aux_stat & AUX_CRLF)
					c=0;
				break;
			case 8:			/* BS */
			case 127:		/* DEL */
				if(in_len && auxbuf[in_len-1]!=0x0a)
				{
					--in_len;
					write_ser("\010 \010",3);
				}
				c=0;
				break;
			case 24: 		/* ^X */
			case 21:		/* ^U */
				while(in_len && auxbuf[in_len-1]!=0x0a)
				{
					--in_len;
					write_ser("\010 \010",3);
				}
				c=0;
				break;
			case 27:		/* <ESC> */
				c=0;
			default:
				break;
			}
			if(c)
				auxbuf[in_len++]=c;

			if(aux_stat & AUX_ECHO)
			{
				if((aux_stat & AUX_CRLF) && c==0x0a)
					puts_ser("\r",1);
				puts_ser(&c,1);
			}
			if(c==0x0a)
				aux_avail++;  /* always done when CR received */
		}
	}

	if(in_len>=MAXLINESIZE)
	{
		aux_stat|=AUX_TYPEAHEAD_FULL;
		if(!aux_avail && (Mode==MODE_CONSOLE))
		{
			aux_avail++;
			auxbuf[in_len++]=0x0a;
		}
		return 0;	/* buffer is full */
	}
	return -1;
}

/*  Write 'em out one by one converting to CR LF if enabled. */
void write_ser(UBYTE *buf,int len)
{	static UBYTE last=0;
	int i,count=0;
	UBYTE c;

	if((aux_stat & AUX_CRLF) || (Mode!=MODE_RAW))
	{
		for(i=0;i<len;i++)
		{
			c=buf[i];
			if(aux_stat & AUX_CRLF)
			{
				if(c==0x9b)
				{
					last=0x9b;
					continue;
				}
				if(last==0x0a && c==0x0d) continue;	/* we already sent CR */
				if(last==0x9b)
				{
					outbuf[count++]='\033';	/* <csi> is converted to ANSI-format */
					outbuf[count++]='[';
				}
			}
			outbuf[count++]=last=c;	/* if we didn't have CR after LF, we add it */
			if(aux_stat & AUX_CRLF)
			{
				if(last==0x0a)
					outbuf[count++]=0x0d;
			}
			if(count+4>OUTBUFSIZE)	/* 3 bytes may be added in one pass */
			{
				puts_ser(outbuf,count);
				count=0;
			}
		}
		if(count)	/* something still to send */
		{
			puts_ser(outbuf,count);
		}
	}
	else
	{
		puts_ser(buf,len);	/* in raw and nocrlf -mode just send the buffer */
		last=buf[len-1];
	}
}

/* write whole buffer */
void puts_ser(UBYTE *buf,int len)
{
	WriteSER->IOSer.io_Length=len;
	WriteSER->IOSer.io_Data=(APTR)buf;
	DoIO((struct IORequest *)WriteSER);
}


int open_stuff()
{
	if(!(auxbuf=(char *)AllocMem(AUXBUFSIZE,MEMF_CLEAR)))
		return 0;

	ReadSER =(struct IOExtSer *)AllocMem(sizeof(*ReadSER),MEMF_PUBLIC|MEMF_CLEAR);
	WriteSER=(struct IOExtSer *)AllocMem(sizeof(*ReadSER),MEMF_PUBLIC|MEMF_CLEAR);
	QuerySER=(struct IOExtSer *)AllocMem(sizeof(*ReadSER),MEMF_PUBLIC|MEMF_CLEAR);

	if(!ReadSER || !WriteSER || !QuerySER)
	{
		goto endser;
	}

	ReadSER->IOSer.io_Message.mn_ReplyPort=(struct MsgPort *)CreatePort(0,0);
	ReadSER->io_SerFlags=serflags;	/* Must be defined here!! */

	if(OpenDevice(device,unitnum,(struct IORequest *)ReadSER,NULL))
	{
		ReadSER->IOSer.io_Device=NULL;
		goto endser;
	}

	ReadSER->IOSer.io_Command	= SDCMD_SETPARAMS;
	ReadSER->io_ExtFlags		= 0L;
	ReadSER->io_SerFlags		= serflags;
	/* normally CTS/RTS handshake - 8-bit protocol with no parity (RAD_BOOGIE) */
	/* if speed is set in the filename part */
	if(SerialSpeed!=-1)
	{
		ReadSER->io_Baud=SerialSpeed;
	}
	DoIO((struct IORequest *)ReadSER);	/* if it didn't work, let the user worry :-) */

	/* Make copies of the structs */
	movmem((UBYTE *)ReadSER,(UBYTE *)WriteSER,sizeof(struct IOExtSer));
	WriteSER->IOSer.io_Command=CMD_WRITE;
	WriteSER->IOSer.io_Message.mn_ReplyPort=NULL;
	movmem((UBYTE *)ReadSER,(UBYTE *)QuerySER,sizeof(struct IOExtSer));
	QuerySER->IOSer.io_Command=SDCMD_QUERY;
	QuerySER->IOSer.io_Message.mn_ReplyPort=NULL;

	if(!(WriteSER->IOSer.io_Message.mn_ReplyPort=(struct MsgPort *)CreatePort(0,0)))
	{
		goto endser;
	}

	if(!(QuerySER->IOSer.io_Message.mn_ReplyPort=(struct MsgPort *)CreatePort(0,0)))
	{
		goto endser;
	}

	/* Open Timer.device */
	if(Timer_Port=(struct MsgPort *)CreatePort(0,0))
	{
		if((Timer=(struct timerequest *)CreateExtIO(Timer_Port,sizeof(*Timer))))
		{
			if(!(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)Timer,0L)))
			{
				Timer->tr_node.io_Command =TR_ADDREQUEST;
				Timer->tr_node.io_Flags =0;
				Timer->tr_node.io_Error =0;
				set_read();	/* start reading immediately */
				return 1;
			}
		}
	}
	Timer->tr_node.io_Device=NULL;
	close_timer();
endser:
	close_ser();
	return 0;
}

void close_ser()
{
	if(auxbuf)
	{
		FreeMem(auxbuf,AUXBUFSIZE);
		auxbuf=NULL;
	}
	if(ReadSER)
	{
		if(ReadSER->IOSer.io_Device)
			CloseDevice((struct IORequest *)ReadSER);
		if(ReadSER->IOSer.io_Message.mn_ReplyPort)
			DeletePort(ReadSER->IOSer.io_Message.mn_ReplyPort);
		FreeMem(ReadSER,sizeof(*ReadSER));
		ReadSER=NULL;
	}
	if(WriteSER)
	{
		if(WriteSER->IOSer.io_Message.mn_ReplyPort)
			DeletePort(WriteSER->IOSer.io_Message.mn_ReplyPort);
		FreeMem(WriteSER,sizeof(*WriteSER));
		WriteSER=NULL;
	}
	if(QuerySER)
	{
		if(QuerySER->IOSer.io_Message.mn_ReplyPort)
			DeletePort(QuerySER->IOSer.io_Message.mn_ReplyPort);
		FreeMem(QuerySER,sizeof(*QuerySER));
		QuerySER=NULL;
	}
	SerialSpeed=-1;
}

void close_timer()
{
	if(Timer)
	{
		if(Timer->tr_node.io_Device)
			CloseDevice((struct IORequest *)Timer);
		DeleteExtIO((struct IORequest *)Timer);
	}
	if(Timer_Port)
		DeletePort(Timer_Port);
}

void chk_file(char *name)
{	register char *s=name;

	strcpy(device,SERIALNAME);	  /* set the defaults */
	unitnum=0;
	aux_stat=AUX_CRLF;
	serflags=SERF_7WIRE | SERF_RAD_BOOGIE | SERF_XDISABLED;
	checkcd=0;
	SerialSpeed=-1;
	Mode=MODE_RAW;

	if(!*s)
		return;	/* no params */

	while(*s && *s!='/')
		s++;
	if(!*s)
	{
		strcpy(device,name);
		return;	/* no unit number */
	}

	unitnum=atoi(s+1);
	strncpy(device,name,(long)(s-name));
	device[(long)(s-name)]='\0';

	s++;

	while(1)
	{
		while(*s && *s!='/')
			s++;
		if(!*s)
			break;
		++s;
		if(!strncmp(s,"raw",3))
		{	aux_stat&=~AUX_ECHO;
			Mode=MODE_RAW;
			s+=3;
		}
		else
		if(!strncmp(s,"con",3))
		{	aux_stat|=AUX_ECHO;
			Mode=MODE_CONSOLE;
			s+=3;
		}
		else
		if(!strncmp(s,"shared",6))
		{	serflags|=SERF_SHARED;
			s+=6;
		}
		else
		if(!strncmp(s,"exclusive",9))
		{	serflags&=~SERF_SHARED;
			s+=9;
		}
		else
		if(!strncmp(s,"noflow",6))
		{	serflags&=~SERF_7WIRE;
			s+=6;
		}
		else
		if(!strncmp(s,"7wire",5))
		{	serflags|=SERF_7WIRE;
			s+=5;
		}
		else
		if(!strncmp(s,"checkcd",7))
		{	checkcd=-1;
			s+=7;
		}
		else
		if(!strncmp(s,"speed",5))
		{
			SerialSpeed=atol(s+=5);
		}
	}
}

/*
 *  misc.c  - support routines - Phillip Lindsay (C) Commodore 1986
 *  You may freely distribute this source and use it for Amiga Development -
 *  as long as the Copyright notice is left intact.
 *
 * 30-SEP-86
 *
 */

/* returnpkt() - packet support routine
 * here is the guy who sends the packet back to the sender...
 */

void returnpkt(struct DosPacket *packet,struct Process *myproc,ULONG res1,ULONG res2)
{	register struct Message *mess=packet->dp_Link;
	register struct MsgPort *replyport=packet->dp_Port;

	packet->dp_Res1      =res1;
	packet->dp_Res2      =res2;
	packet->dp_Port      =&myproc->pr_MsgPort;
	mess->mn_Node.ln_Name=(char *) packet;
	mess->mn_Node.ln_Succ=mess->mn_Node.ln_Pred=NULL;
	PutMsg(replyport, mess);
}


/*
 * taskwait() ... Waits for a message to arrive at your port and
 *   extracts the packet address which is returned to you.
 */

struct DosPacket *taskwait(struct Process *myproc)
{	register struct MsgPort *myport=&myproc->pr_MsgPort;
	register struct Message *mymess;

	WaitPort(myport);
	mymess=(struct Message *)GetMsg(myport);
	return((struct DosPacket *)mymess->mn_Node.ln_Name);
}

/* end of misc.c    */

