/***************************************************************************\
*
*	NEWAUX:serial.device/0/con/exclusive/7wire/speed<speed>/checkcd/useodu
*						  /raw/shared/noflow/
*	NEWAUX:break<channel>
*	NEWAUX:tobuf<channel>/<text>	- the text will be converted to lower-case!
*	NEWAUX:led<ledmask>
*
*	channel is a number from 0 to 15,
*	the lowest possible number will be selected when a new serial is opened.
*
*	The aux driver by Steve Drew was used as an example for the first version.
*
*	Aux Driver V1.0 (c)CopyRight 1987, Steve Drew.
*
*	Steve Drew
*	52-Castledale Cres. N.E.
*	Calgary, Ab. Canada.
*
*
*	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
*	NEWAUX		Ver. 1.3  19-Aug-1993	Multiple lines with one handler
*										More efficient Raw-mode handling
*										Uses OwnDevUnit.library!
*				Ver. 1.31 20-Aug-1993	Asynchronous passthrough mode writes
*				Ver. 1.32 29-Oct-1993	Carrier checked also when writing..
*				Ver. 1.33 04-Feb-1994	Two simultaneous writes handled..
*				Ver. 1.34 30-Dec-1994	Possible to force EOF
*
*	Pasi Ojala		albert@cs.tut.fi
*	Telkontie 50	albert@cc.tut.fi
*	39230 Osara
*
NEWAUX:
	Handler = L:NEWAUX-Handler
	Stacksize = 2000
	Priority = 5
	GlobVec = 1
#

TAB size is 4!
\****************************************************************************/

#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 <clib/timer_protos.h>
#include <stdlib.h>
#include <string.h>
#include <other/OwnDevUnit.h>

int tolower(int);

const static char vers[] = "\0$VER: NEWAUX-Handler 1.35 (24.4.1995)\n";

#define LED_SYNCREAD		1
#define LED_ASYNCREAD		2
#define LED_SYNCWRITE		4
#define LED_ASYNCWRITE		8
#define LED_QUERY			16
#define LED_MESSAGE			32


#undef  BADDR
#define BADDR(x)	((APTR)((long)x << 2))

#if 0
/* 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
#endif

#define ACTION_QUERY		64	/* our own non-standard action */

#define MODE_NONCOOKED		(-1)/* Synonym for plain MODE_RAW for compatibility */
#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 MODE_EOF			4   /* Forced EOF -- BEWARE: Can only be set!! */

#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_USEODU			4	/* Use OwnDevUnit.library for locking */
#define AUX_LOCKED			8
#define AUX_CHECKCD			16
#define AUX_CMD_READ		32	/* serial CMD_READ active */
#define AUX_CMD_WRITE		64	/* serial CMD_WRITE active */
#define AUX_NONCONCURRENT	128 /* the serial is not able to service concurrent requests */
#define AUX_EOF_FORCED		256 /* EOF forced by software */

#define AUXBUFSIZE			8192			/* typeahead/edit buffer size */
#define MAXLINESIZE			AUXBUFSIZE-2	/* save two for \n\0  */
#define OUTBUFSIZE			2048			/* Temporary buffer for synchronous writes */
#define TEMPBUFSIZE			1024			/* Temporary buffer for synchronous reads and writes */
#define DEVICENAMELEN		32
#define MAXCNX				16

#define CD_CHECK_COUNT		4096			/* check carrier once in CD_CHECK_COUNT chars written */


#define MYPORT_SIG	(1L<<myport->mp_SigBit)		/* signal bit for requests */
#define TIMER_SIG	(1L<<timerreply->mp_SigBit)
#define WRITE_SIG	(1L<<writereply->mp_SigBit)

/* Prototypes */

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

int ret_readpacket(struct Connection *, struct Process*);

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

void chk_file(char *, struct Connection *);

void __saveds handler(void);

VOID 			*SysBase;
struct Library *TimerBase = NULL;
struct Library *OwnDevUnitBase = NULL;
struct MsgPort	*tempreply  = NULL;
struct MsgPort	*writereply = NULL;
struct MsgPort	*timerreply = NULL;
ULONG			portsignum = 0;
UBYTE			tempbuf[TEMPBUFSIZE+1];
ULONG			led;


/* Global, per-connection information */

struct Connection
{
	struct	MsgPort cnxport;
	char	devicename[DEVICENAMELEN];
	long	deviceunit;
	long	devicespeed;
	long	deviceflags;
	long	devicestatus;

	int		aux_open;	/* Open count */

	struct	IOExtSer	*ReadSER;
	struct	IOExtSer	*WriteSER;
	struct	IOExtSer	*TempSER;
	struct	timerequest	*Timer;
	struct	MsgPort		*Timer_Port;

	struct	DosPacket	*rdpkt, *waitpkt, *writepkt, *writepkt2;

	struct	Task	*owner;			/* the first opener (for Reopen) */
	struct	Task	*reader;		/* the opener that gets signals */
	UBYTE			last;			/* last byte sent */
	UBYTE			in_c;			/* async read buffer */
	UBYTE			breakallowed;
	UBYTE			Mode;
	int				aux_stat;		/* aux flags */
	int				aux_avail;		/* available lines in buffer (cooked mode) */
	int				in_len;			/* available bytes in buffer (raw mode) */
	int				ser_len;		/* bytes in serial device buffer (approx.) */
	int				write_count;	/* bytes sent since last carrier check */
	UBYTE			auxbuf[AUXBUFSIZE+1];	/* type ahead buffer */
	UBYTE			outbuf[OUTBUFSIZE+1];	/* async write buffer */
};


void __saveds handler()	/* this is kinda main() */
{
	struct Process		*myproc;		/* my process */
	struct DosPacket	*mypkt;
	struct DeviceNode	*mynode; 		/* our device node (parmpkt Arg3) */
	struct MsgPort		*myport;
	struct FileHandle	*fh;
	BOOL				run = TRUE;		/* handler main loop flag */
	UBYTE				*ptr;			/* ptr for name translation */
	char				*s;				/* ptr to name for open */
	int					i, tmp;
	char				name[200];		/* filename passed to */
	struct Connection	*cnx[MAXCNX], *cc;
	int					cnxs, cn;
	long				signals, sigmask;

	/* 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);

	/* Shared replyports */
	/* tempreply is used with DoIO() (CMD_WRITE and SDCMD_QUERY) */
	/* timerreply is the replyport for all timer requests. */
	/* This way we have enough signals to serve quite many channels.. */

	portsignum = AllocSignal(-1);
	tempreply  = (struct MsgPort *)CreatePort(0, 0);
	timerreply = (struct MsgPort *)CreatePort(0, 0);
	writereply = (struct MsgPort *)CreatePort(0, 0);

	for(cn=0;cn<MAXCNX;cn++)
		cnx[cn] = NULL;
	cnxs = 0;

	/* Open OwnDevUnit.library or not.. */
	OwnDevUnitBase = OpenLibrary(ODU_NAME, 0);

	/* done initial stuff, now for some work */
	while(run)
	{
		if(cnxs)	/* if any connections open, wait for read char or new action */
		{
			/* Create signal mask for active channels */
			sigmask = 0;
			for(cn=0;cn<MAXCNX;cn++)
			{
				if(cnx[cn])
					sigmask |= (1L<<cnx[cn]->ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
			}

			signals = Wait(MYPORT_SIG | TIMER_SIG | WRITE_SIG | sigmask | (1<<portsignum));

			/* WaitForChar() timeout */
			if((signals & TIMER_SIG))
			{
				for(cn=0;cn<MAXCNX;cn++)
				{
					if(	cnx[cn] &&
						cnx[cn]->waitpkt &&
						CheckIO((struct IORequest *)cnx[cn]->Timer))
					{
						WaitIO((struct IORequest *)cnx[cn]->Timer);

						cnx[cn]->ser_len = query_ser(cnx[cn]);

						if((cnx[cn]->aux_stat & AUX_EOF_FORCED) ||
						   ((cnx[cn]->aux_stat & AUX_CHECKCD) && (cnx[cn]->devicestatus & (1L<<5))))
						{
							/* CD dropped */
							if(cnx[cn]->waitpkt->dp_Port->mp_SigTask)
								Signal(cnx[cn]->waitpkt->dp_Port->mp_SigTask, SIGBREAKF_CTRL_C);
							returnpkt(cnx[cn]->waitpkt, myproc, DOS_TRUE, cnx[cn]->in_len);
							/* EOF can be read :-) */
						}
						else if(cnx[cn]->in_len)	/* TODO: handle chars in serial buffer */
						{
							returnpkt(cnx[cn]->waitpkt, myproc, DOS_TRUE, cnx[cn]->in_len);
						}
						else
						{
							returnpkt(cnx[cn]->waitpkt, myproc, DOS_FALSE, cnx[cn]->waitpkt->dp_Res2);
						}
						cnx[cn]->waitpkt = NULL;
					}
				}
			}

			/* Read() returned */
			if((signals & sigmask))
			{
				for(cn=0;cn<MAXCNX;cn++)
				{
					if(cnx[cn] && (cnx[cn]->aux_stat & AUX_CMD_READ) &&
					/*	(signals & (1L<<cnx[cn]->ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit)) && */
						CheckIO((struct IORequest *)cnx[cn]->ReadSER))
					{
						/* fine, got a char */
						WaitIO((struct IORequest *)cnx[cn]->ReadSER);
						cnx[cn]->aux_stat &= ~AUX_CMD_READ;

						if(led & LED_ASYNCREAD)
							*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

						/* Buffer the character just read */
						if(buf_ser(cnx[cn], &cnx[cn]->in_c, 1))
						{
							/* Anything else in the serial buffer ? */
							cnx[cn]->ser_len = tmp = query_ser(cnx[cn]);
							if(tmp && AUXBUFSIZE-cnx[cn]->in_len-2 > 10)
							{
								if(tmp > AUXBUFSIZE-cnx[cn]->in_len-9)
									tmp = AUXBUFSIZE-cnx[cn]->in_len-10;	/* hysteresis */
								if(tmp > TEMPBUFSIZE)
									tmp = TEMPBUFSIZE;

								get_ser(cnx[cn], tempbuf, tmp);
								buf_ser(cnx[cn], tempbuf, tmp);
								cnx[cn]->ser_len -= tmp;
							}
							/* because buffer is not full, start another read */
							/* In raw mode we wait for the next read request */
							if(cnx[cn]->Mode != MODE_RAW)
								set_read(cnx[cn]);
						}
						/* If buf_ser returns false, the buffer is full and we */
						/* don't start another read request. */

						/* Someone waiting for characters ? */
						if(cnx[cn]->waitpkt)
						{
							AbortIO((struct IORequest *)cnx[cn]->Timer);
							WaitIO((struct IORequest *)cnx[cn]->Timer);
							/* Wait(TIMER_SIG); */
							/* We don't need to clear the signal */
							if((cnx[cn]->aux_stat & AUX_EOF_FORCED) ||
							   ((cnx[cn]->aux_stat & AUX_CHECKCD) && (cnx[cn]->devicestatus & (1L<<5))))
							{
								/* CD dropped */
								if(cnx[cn]->waitpkt->dp_Port->mp_SigTask)
									Signal(cnx[cn]->waitpkt->dp_Port->mp_SigTask, SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
								returnpkt(cnx[cn]->waitpkt, myproc, DOS_TRUE, cnx[cn]->in_len);
								/* EOF can be read :-) */
							}
							else
							{
								returnpkt(cnx[cn]->waitpkt, myproc, DOS_TRUE, cnx[cn]->in_len+cnx[cn]->ser_len);
							}
							cnx[cn]->waitpkt = NULL;
						}
						if(cnx[cn]->rdpkt)
						{
							ret_readpacket(cnx[cn], myproc); /* Either returs the packet or not */
						}
					}
				}
			}

			/* Write returned, check which one.. */
			if(signals & WRITE_SIG)
			{
				for(cn=0;cn<MAXCNX;cn++)
				{
					if(cnx[cn] && (cnx[cn]->aux_stat & AUX_CMD_WRITE) &&
						CheckIO((struct IORequest *)cnx[cn]->WriteSER))
					{
						cc = cnx[cn];

						if(led & LED_ASYNCWRITE)
							*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

						cc->aux_stat &= ~AUX_CMD_WRITE;
						returnpkt(cc->writepkt, myproc, cc->writepkt->dp_Arg3, cc->writepkt->dp_Res2);
						cc->writepkt = NULL;
						if(cc->writepkt2)
						{
							if(write_ser(cc, (char *)cc->writepkt2->dp_Arg2, (int)cc->writepkt2->dp_Arg3))
							{
								/* Write finished already */
								returnpkt(cc->writepkt2, myproc, cc->writepkt2->dp_Arg3, cc->writepkt2->dp_Res2);
								cc->writepkt2 = NULL;
							}
							else
							{
								/* Asynchronous write */
								if(led & LED_ASYNCWRITE)
									*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

								cc->aux_stat |= AUX_CMD_WRITE;
								cc->writepkt = cc->writepkt2;
								cc->writepkt2 = NULL;
							}
						}
					}
				}
			}

			if(signals & (1L<<portsignum))	/* Reopen or action request */
			{
/* TODO: First see what connection, then process */
				for(cn=0;cn<MAXCNX;cn++)
				{
					if(cc = cnx[cn])
					{
						struct Message *mymess;

						while(cc && (mymess = (struct Message *)GetMsg(&cc->cnxport)))
						{
							mypkt = (struct DosPacket *)mymess->mn_Node.ln_Name;

							if(led & LED_MESSAGE)
								*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */
							switch(mypkt->dp_Type)
							{
							case ACTION_FINDINPUT:
							case ACTION_FINDUPDATE:
							case ACTION_FINDOUTPUT:
								/* We assume that it is the same channel, */
								/* Otherwise we would have get it to the task msgport */

								/* We allow multiple readers and writers, but only
								   the first reader will get the signals */

								cc->aux_open++;
								if(mypkt->dp_Type == ACTION_FINDINPUT || mypkt->dp_Type == ACTION_FINDUPDATE)
								{
									/* Have I already got someone reading ? NOT! */
									if(!cc->reader)
									{
										cc->reader = mypkt->dp_Port->mp_SigTask;
										cc->breakallowed = 0;
									}
								}
								fh = (struct FileHandle *)BADDR(mypkt->dp_Arg1);
								fh->fh_Arg1 = ((LONG)cc) >> 2;
								fh->fh_Port = (struct MsgPort *)DOS_TRUE;
								fh->fh_Type = &cnx[cn]->cnxport;

								returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
								break;

							case ACTION_READ:	/* Someone made a Read() */
								if(cc->rdpkt)
								{
									if(cc->rdpkt->dp_Arg3>=15)
									{
										movmem("Another reader\n", (UBYTE *)mypkt->dp_Arg2, 15);
										returnpkt(mypkt, myproc, 15, mypkt->dp_Res2);
									}
									else
									{
										returnpkt(mypkt, myproc, DOS_FALSE, mypkt->dp_Res2);
									}
									break;
								}

								cc->rdpkt = mypkt;
								cc->ser_len = query_ser(cc);
								(void)ret_readpacket(cc, myproc); /* Either returs or not */
								break;

							case ACTION_WRITE:	/* tell 'em we wrote them all */
								/* we have a pending write */
								if(cc->writepkt)
								{
									if(cc->writepkt2)
									{
										returnpkt(mypkt, myproc, DOS_FALSE, mypkt->dp_Res2);
									}
									else
									{
										cc->writepkt2 = mypkt;
										mypkt=NULL;
									}
									break;
								}
								if(write_ser(cc, (char *)mypkt->dp_Arg2, (int)mypkt->dp_Arg3))
								{
									/* Write finished already */
									returnpkt(mypkt, myproc, mypkt->dp_Arg3, mypkt->dp_Res2);
								}
								else
								{
									/* Asynchronous write */
									if(led & LED_ASYNCWRITE)
										*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

									cc->aux_stat |= AUX_CMD_WRITE;
									cc->writepkt = mypkt;
								}
								break;

							case ACTION_WAIT_CHAR:		/* just queue up to wait for data */
								if(cc->waitpkt)	/* Someone already waiting.. */
								{
									returnpkt(mypkt, myproc, DOS_TRUE, 15);
									break;
								}

								cc->waitpkt = mypkt;
								cc->ser_len = query_ser(cc);
								if((cc->aux_stat & AUX_EOF_FORCED) ||
								   ((cc->aux_stat & AUX_CHECKCD) && (cc->devicestatus & (1L<<5))))	/* CD dropped */
								{
									if(cc->waitpkt->dp_Port->mp_SigTask)
										Signal(cc->waitpkt->dp_Port->mp_SigTask, SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
									returnpkt(cc->waitpkt, myproc, DOS_TRUE, cc->in_len+cc->ser_len);
									/* EOF can be read :-) */
									cc->waitpkt = NULL;
									break;
								}

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

								/*cc->Timer->tr_node.io_Command = TR_ADDREQUEST;*/
								cc->Timer->tr_time.tv_secs = 0L;
								cc->Timer->tr_time.tv_micro= cc->waitpkt->dp_Arg1;
								SendIO((struct IORequest *)cc->Timer);
								set_read(cc);	/* Send a read request if not yet active */

								break;

							case ACTION_SCREEN_MODE:
								cc->breakallowed = TRUE;	/* Break (^c or ^d) is allowed only after setmode */
								cc->aux_stat |= AUX_ECHO;
								cc->Mode = MODE_CONSOLE;
								if(mypkt->dp_Arg1 == -1)	/* -1 means 'normal' Raw mode */
								{
									cc->Mode = MODE_RAW;
									cc->aux_stat |= AUX_CRLF;
									cc->aux_stat &= ~AUX_ECHO;
								}
								else
								{
									if(mypkt->dp_Arg1 & MODE_EOF)
									{
										cc->aux_stat |= AUX_EOF_FORCED;
										/* Can only be set !! */
									}
									else
									{
										if(mypkt->dp_Arg1 & MODE_RAW)	/* raw means RAW and NOECHO */
										{
											cc->aux_stat &= ~AUX_ECHO;
											cc->Mode = MODE_RAW;
										}
										if(mypkt->dp_Arg1 & MODE_NOCRLF)	/* NOCRLF possible in console mode too */
										{
											cc->aux_stat &= ~AUX_CRLF;
										}
										else
										{
											cc->aux_stat |= AUX_CRLF;
										}
									}
								}
								returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
								/* Start reading again if we changed to cooked mode */
								if(cc->Mode == MODE_CONSOLE && !(cc->aux_stat & AUX_CMD_READ))
									set_read(cc);
								break;

							case ACTION_QUERY:
								cc->ser_len = query_ser(cc);
								returnpkt(mypkt, myproc, DOS_TRUE, cc->devicestatus);
								break;

							case ACTION_END:
								/* The reader closing ? */
								if(cc->reader == mypkt->dp_Port->mp_SigTask)
									cc->reader = (struct Task *)NULL;

								/* Decrease the open count. Any users left? NO! */
								if(--cc->aux_open == 0)
								{
									/* Close the timer.device for this connection */
									close_timer(cc);

									/* Close the serial and free ports etc. */
									close_ser(cc);

									/* TODO: return possible requests */

									FreeMem(cc, sizeof(struct Connection));
									cc = (struct Connection *)NULL;
									cnx[cn] = (struct Connection *)NULL;
									cnxs--;
									if(!cnxs)
										run = FALSE;
								}
								returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
								break;

							case ACTION_DISK_INFO:	/* This is not really a console handler! */
							default:
								returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
								break;
							}
							if(led & LED_MESSAGE)
								*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */
						}
					}
				}
			}
			if(signals & MYPORT_SIG)		/* Someone sent an open request */
			{
				mypkt = taskwait(myproc);
/* open */
			}
			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 */
/* open */
		}

		if(led & LED_MESSAGE)
			*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */
		switch(mypkt->dp_Type)				/* find what action to perform */
		{
		case ACTION_FINDINPUT:		/* Someone made Open() */
		case ACTION_FINDUPDATE:
		case ACTION_FINDOUTPUT:
			/*	Multiple writers are allowed. */
			/* get file name and Lower 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, "*") || !strncmp(name, "console:", 8))
			{
				/* the same channel ("*" or "console:") */

				/* We have to see what channel belongs to the task,   */
				/* because we return the same msgport for all openers */
				for(i=0;i<MAXCNX;i++)
				{
					if(cnx[i] && cnx[i]->owner == mypkt->dp_Port->mp_SigTask)
					{
						break;
					}
				}
				if(i==MAXCNX)	/* Couldn't find the channel */
				{
					returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
					break;
				}
				cnx[i]->aux_open++;
			}
			else
			{
				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++;			/* skip the colon */
				}

				if(!strncmp(s, "led", 3))	/* newaux:led<mask> */
				{
					led = atoi(s+3);		/* Get led mask */
					if(led & LED_MESSAGE)
						*(UBYTE *)0xbfe001 &= ~2;	/* Set led */
					else
						*(UBYTE *)0xbfe001 |= 2;	/* Unset led */

					returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
					break;
				}
				if(!strncmp(s, "tobuf", 5))	/* newaux:tobuf<channel>/text */
				{
					s+=5;					/* Skip TOBUF */
					tmp = atoi(s);			/* Get channel number */
					while(*s && *s != '/')	/* Skip number */
						s++;
					if(*s == '/')
						s++;
					strcat(s, "\n");			/* add newline */

					if(cnx[tmp] && AUXBUFSIZE-cnx[tmp]->in_len>strlen(s))
					{
						buf_ser(cnx[tmp], s, strlen(s));
						if(cnx[tmp]->rdpkt)
						{
							if(cnx[tmp]->aux_stat & AUX_CMD_READ)
							{
								AbortIO((struct IORequest *)cnx[tmp]->ReadSER);
								WaitIO((struct IORequest *)cnx[tmp]->ReadSER);
								Wait(1L<<cnx[tmp]->ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
								cnx[tmp]->aux_stat &= ~AUX_CMD_READ;
							}
							ret_readpacket(cnx[tmp], myproc); /* Either returs or not */
						}
					}
					returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
					break;
				}
				if(!strncmp(s, "break", 5))	/* newaux:break<channel> */
				{
					tmp = atoi(s+5);		/* Get channel number */

					if(cnx[tmp] && cnx[tmp]->reader)
					{
						Signal(cnx[tmp]->reader, SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
					}
					returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
					break;
				}

				if((cc = (struct Connection *)AllocMem(sizeof(struct Connection), MEMF_PUBLIC | MEMF_CLEAR)))
				{
					chk_file(s, cc);
					for(i=0;i<MAXCNX;i++)
					{
						if(cnx[i] && !strcmp(cnx[i]->devicename, cc->devicename) &&
							cnx[i]->deviceunit == cc->deviceunit)
						{
							FreeMem(cc, sizeof(struct Connection));
							break;
						}
					}
					if(i==MAXCNX)
					{
						/* Open a new serial */
						if(!(cc->aux_open = open_stuff(cc)))
						{
							FreeMem(cc, sizeof(struct Connection));
							returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
							break;
						}
						cc->owner = mypkt->dp_Port->mp_SigTask;
						i=0;
						while(cnx[i])
							i++;
						cnx[i] = cc;
/* init the port */
						NewList(&cnx[i]->cnxport.mp_MsgList);
						cnx[i]->cnxport.mp_SigTask = myproc;
						cnx[i]->cnxport.mp_SigBit = portsignum;
						cnxs++;
					}
					else
					{
						/* Reopen a channel */
						cnx[i]->aux_open++;
					}
				}
				else
				{
					returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
					break;
				}
			}

			if(mypkt->dp_Type == ACTION_FINDINPUT || mypkt->dp_Type == ACTION_FINDUPDATE)
			{
				/* Have I already got someone reading ? NOT! */
				if(!cnx[i]->reader)
				{
					cnx[i]->reader = mypkt->dp_Port->mp_SigTask;
					cnx[i]->breakallowed = 0;
				}
				else
				{
					/* Decrease the open count. Any users left? NO! */
					if(--cnx[i]->aux_open == 0)
					{
						/* Close the timer.device for this connection */
						close_timer(cnx[i]);

						/* Close the serial and free ports etc. */
						close_ser(cnx[i]);
						FreeMem(cnx[i], sizeof(struct Connection));
						cnx[i] = (struct Connection *)NULL;

						cnxs--;
						if(!cnxs)
							run = FALSE;
					}
					returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
					break;
				}
			}
			fh = (struct FileHandle *)BADDR(mypkt->dp_Arg1);
			fh->fh_Arg1 = ((LONG)cnx[i]) >> 2;
			fh->fh_Port = (struct MsgPort *)DOS_TRUE;
			fh->fh_Type = &cnx[i]->cnxport;

			returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
			break;
		case ACTION_DISK_INFO:	/* This is not really a console handler! */
		default:
			returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
			break;
		}
		if(led & LED_MESSAGE)
			*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */
	}
	mynode->dn_Task = FALSE;
	/* Delete shared replyports before exiting.. */

	DeletePort(tempreply);
	DeletePort(timerreply);
	DeletePort(writereply);
	FreeSignal(portsignum);
	if(OwnDevUnitBase)
		CloseLibrary(OwnDevUnitBase);
}


/* Return the read request */
int ret_readpacket(struct Connection *cc, struct Process *myproc)
{
	UBYTE *ptr;
	int i, tmp;

	if((cc->aux_stat & AUX_EOF_FORCED) ||
	   ((cc->aux_stat & AUX_CHECKCD) && (cc->devicestatus & (1L<<5))))
	{
		/* CD dropped */
		if(cc->rdpkt->dp_Port->mp_SigTask)
			Signal(cc->rdpkt->dp_Port->mp_SigTask, SIGBREAKF_CTRL_C);

		/* for programs that donīt pay attention to the return code of Read() */
		if(cc->rdpkt->dp_Arg3)
			*((UBYTE *)cc->rdpkt->dp_Arg2) = 0x03;

		returnpkt(cc->rdpkt, myproc, DOS_FALSE, cc->rdpkt->dp_Res2);
		/* return EOF */
		cc->rdpkt = NULL;
		return -1;
	}

	if(cc->Mode == MODE_RAW)
	{
		/*  Ok, nothing in our buffer, nothing in the serial buffer, 
			so just wait for the next byte to arrive */
		if((cc->in_len + cc->ser_len) == 0)
		{
			set_read(cc);
			return 0;
		}

		/* We have less than wanted! */
		if(cc->in_len < cc->rdpkt->dp_Arg3)
		{
			if(cc->in_len)
				movmem(cc->auxbuf, (UBYTE *)cc->rdpkt->dp_Arg2, cc->in_len);
			i = cc->in_len;
			cc->aux_avail = cc->in_len = 0;

			if(cc->ser_len)
			{
				/* How much still fits ? */
				tmp = cc->rdpkt->dp_Arg3-i;

				/* serial buffer has less than needed */
				if(cc->ser_len < tmp)
				{
					tmp = cc->ser_len;
					get_ser(cc, (UBYTE *)cc->rdpkt->dp_Arg2+i, tmp);
					cc->ser_len = 0;
				}
				else
				{
					get_ser(cc, (UBYTE *)cc->rdpkt->dp_Arg2+i, tmp);
					cc->ser_len -= tmp;
				}
				i += tmp;
			}
		}
		else	/* Enough in buffer to satisfy the request */
		{
			i = cc->rdpkt->dp_Arg3;
			movmem(cc->auxbuf, (UBYTE *)cc->rdpkt->dp_Arg2, i);

			cc->in_len -= i;
			movmem(cc->auxbuf+i, cc->auxbuf, cc->in_len);
			cc->aux_avail = tmp = 0;
			while(tmp<cc->in_len)
				if(cc->auxbuf[tmp++] == '\n')
					cc->aux_avail++;
		}
		returnpkt(cc->rdpkt, myproc, (long)i, cc->rdpkt->dp_Res2);
		cc->rdpkt = NULL;
		return -1;
	}
	else
	{
		/* Line waiting ? */
		if(cc->aux_avail)
		{
			cc->aux_avail--;
			i = 0;
			ptr = (UBYTE *)cc->rdpkt->dp_Arg2;
			while(i<cc->rdpkt->dp_Arg3 && i<cc->in_len)
			{
				if((ptr[i] = cc->auxbuf[i]) == '\n')
				{
					i++;
					break;
				}
				i++;
			}

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

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

			if(!(cc->aux_stat & AUX_CMD_READ) && cc->in_len<MAXLINESIZE-1)
			{
				set_read(cc);	/* start waiting for reads again */
			}
			returnpkt(cc->rdpkt, myproc, (long)i, cc->rdpkt->dp_Res2);
			cc->rdpkt = NULL;
			return -1;
		}
	}
	return 0;
}

/*  Start an asynchronous Read request */
void set_read(struct Connection *cnx)
{
	if(!(cnx->aux_stat & AUX_CMD_READ))
	{
		if(led & LED_ASYNCREAD)
			*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

		/* Clear the signal, so that we don't misinterpret it */
		SetSignal(0, (1<<cnx->ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit));

		cnx->ReadSER->IOSer.io_Command= CMD_READ;
		cnx->ReadSER->IOSer.io_Data	  = (APTR)&cnx->in_c;
		cnx->ReadSER->IOSer.io_Length = 1L;
		SendIO((struct IORequest *)cnx->ReadSER);
		cnx->aux_stat |= AUX_CMD_READ;
	}
}

int query_ser(struct Connection *cnx)	/* we use a dedicated IORequest */
{
	int wasactive=0;

	/* TODO: If concurrent requests are not possible, abort read */
	if((cnx->aux_stat & AUX_CMD_READ) && !CheckIO((struct IORequest *)cnx->ReadSER))
	{
		AbortIO((struct IORequest *)cnx->ReadSER);
		WaitIO((struct IORequest *)cnx->ReadSER);
		SetSignal(0, (1L<<cnx->ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit));

		cnx->aux_stat &= ~AUX_CMD_READ;
		wasactive = 1;
		if(led & LED_ASYNCREAD)
			*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */
	}

	if(led & LED_QUERY)
		*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

	cnx->TempSER->IOSer.io_Command = SDCMD_QUERY;
	DoIO((struct IORequest *)cnx->TempSER);

	/* TODO: If concurret requests are not possible, restart read */
	if(wasactive)
	{
		set_read(cnx);
	}

	cnx->devicestatus = cnx->TempSER->io_Status;
	cnx->write_count = 0;
	return (int)cnx->TempSER->IOSer.io_Actual;
}

void get_ser(struct Connection *cnx, UBYTE *destbuf, int size)
{
	if(led & LED_SYNCREAD)
		*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

	cnx->ReadSER->IOSer.io_Command= CMD_READ;
	cnx->ReadSER->IOSer.io_Data	  = (APTR)destbuf;
	cnx->ReadSER->IOSer.io_Length = size;
	DoIO((struct IORequest *)cnx->ReadSER);

	/* Clear the signal, so that we don't misinterpret it */
	SetSignal(0, (1<<cnx->ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit));

	if(led & LED_SYNCREAD)
		*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */
}


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

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

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

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

	if(cnx->in_len >= MAXLINESIZE)
	{
		/*cnx->aux_stat &= ~AUX_CMD_READ;*/
		if(!cnx->aux_avail && (cnx->Mode == MODE_CONSOLE))
		{
			/* Force a newline so that the line can be finally read.. */
			cnx->aux_avail++;
			cnx->auxbuf[cnx->in_len++] = 0x0a;
		}
		return 0;	/* buffer is full */
	}
	return -1;
}

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

	cnx->write_count += len;
	if(cnx->write_count >= CD_CHECK_COUNT)
	{
		cnx->ser_len = query_ser(cnx);
		if((cnx->aux_stat & AUX_EOF_FORCED) ||
		   ((cnx->aux_stat & AUX_CHECKCD) && (cnx->devicestatus & (1L<<5))))	/* CD dropped */
		{
			if(cnx->reader)
				Signal(cnx->reader, SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D);
		}
	}

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

			cnx->WriteSER->IOSer.io_Command = CMD_WRITE;
			cnx->WriteSER->IOSer.io_Length = count;
			cnx->WriteSER->IOSer.io_Data = cnx->outbuf;
			SendIO((struct IORequest *)cnx->WriteSER);

			return 0;	/* Not finished */
		}
		return 1;		/* Finished */
	}
	else
	{
		/* puts_ser(cnx, buf, len);	in raw and nocrlf -mode just send the buffer */

		cnx->WriteSER->IOSer.io_Command = CMD_WRITE;
		cnx->WriteSER->IOSer.io_Length = len;
		cnx->WriteSER->IOSer.io_Data = buf;
		SendIO((struct IORequest *)cnx->WriteSER);

		cnx->last = buf[len-1];
		return 0;	 	/* Write not finished */
	}
}

/* write whole buffer */
void puts_ser(struct Connection *cnx, UBYTE *buf, int len)
{
	if(led & LED_SYNCWRITE)
		*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */

	cnx->TempSER->IOSer.io_Command = CMD_WRITE;
	cnx->TempSER->IOSer.io_Length = len;
	cnx->TempSER->IOSer.io_Data = (APTR)buf;
	DoIO((struct IORequest *)cnx->TempSER);

	if(led & LED_SYNCWRITE)
		*(UBYTE *)0xbfe001 ^= 2;	/* Toggle led */
}


int open_stuff(struct Connection *cnx)
{
	cnx->ReadSER = (struct IOExtSer *)AllocMem(sizeof(*cnx->ReadSER), MEMF_PUBLIC|MEMF_CLEAR);
	cnx->WriteSER= (struct IOExtSer *)AllocMem(sizeof(*cnx->ReadSER), MEMF_PUBLIC|MEMF_CLEAR);
	cnx->TempSER = (struct IOExtSer *)AllocMem(sizeof(*cnx->ReadSER), MEMF_PUBLIC|MEMF_CLEAR);

	if(!cnx->ReadSER || !cnx->WriteSER || !cnx->TempSER)
	{
		goto endser;
	}

	if(OwnDevUnitBase && (cnx->aux_stat & AUX_USEODU))
	{
		if(AttemptDevUnit(cnx->devicename,cnx->deviceunit,(char *)vers+7,0))
		{
			goto endser;
		}
		cnx->aux_stat |= AUX_LOCKED;
	}

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

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

	cnx->ReadSER->IOSer.io_Command	= SDCMD_SETPARAMS;
	cnx->ReadSER->io_ExtFlags		= 0L;
	cnx->ReadSER->io_SerFlags		= cnx->deviceflags;
	/* normally CTS/RTS handshake - 8-bit protocol with no parity (RAD_BOOGIE) */

	/* if speed is set in the filename part */
	if(cnx->devicespeed != -1)
	{
		cnx->ReadSER->io_Baud = (ULONG)cnx->devicespeed;
	}
	DoIO((struct IORequest *)cnx->ReadSER);	/* if it didn't work, let the user worry :-) */

	/* Make copies of the structs (after the SETPARAMS!) */
	movmem((UBYTE *)cnx->ReadSER, (UBYTE *)cnx->WriteSER, sizeof(struct IOExtSer));
	cnx->WriteSER->IOSer.io_Message.mn_ReplyPort = writereply;

	movmem((UBYTE *)cnx->ReadSER, (UBYTE *)cnx->TempSER, sizeof(struct IOExtSer));
	cnx->TempSER->IOSer.io_Message.mn_ReplyPort = tempreply;
#else
	cnx->TempSER->io_ExtFlags =
		cnx->WriteSER->io_ExtFlags =
			cnx->ReadSER->io_ExtFlags = 0L;
	cnx->ReadSER->IOSer.io_Message.mn_ReplyPort =
		(struct MsgPort *)CreatePort(0, 0);
	cnx->TempSER->IOSer.io_Message.mn_ReplyPort = tempreply;
	cnx->WriteSER->IOSer.io_Message.mn_ReplyPort = writereply;
	cnx->TempSER->io_SerFlags =
		cnx->WriteSER->io_SerFlags =
			cnx->ReadSER->io_SerFlags =
				(cnx->deviceflags | SERF_SHARED);	/* Must be defined here!! */

	/* if speed is set in the filename part */
	if(cnx->devicespeed != -1)
	{
		cnx->ReadSER->io_Baud = (ULONG)cnx->devicespeed;
		cnx->WriteSER->io_Baud = (ULONG)cnx->devicespeed;
		cnx->TempSER->io_Baud = (ULONG)cnx->devicespeed;
	}
	if(OpenDevice(cnx->devicename, cnx->deviceunit, (struct IORequest *)cnx->ReadSER, NULL))
	{
		cnx->ReadSER->IOSer.io_Device = NULL;
		goto endser;
	}
	if(OpenDevice(cnx->devicename, cnx->deviceunit, (struct IORequest *)cnx->WriteSER, NULL))
	{
		cnx->WriteSER->IOSer.io_Device = NULL;
		goto endser;
	}
	if(OpenDevice(cnx->devicename, cnx->deviceunit, (struct IORequest *)cnx->TempSER, NULL))
	{
		cnx->TempSER->IOSer.io_Device = NULL;
		goto endser;
	}

	cnx->ReadSER->IOSer.io_Command	= SDCMD_SETPARAMS;
	cnx->ReadSER->io_ExtFlags = 0L;
	cnx->ReadSER->io_SerFlags		= cnx->deviceflags | SERF_SHARED;
	/* normally CTS/RTS handshake - 8-bit protocol with no parity (RAD_BOOGIE) */

	if(cnx->devicespeed != -1)
	{
		cnx->ReadSER->io_Baud = (ULONG)cnx->devicespeed;
		cnx->WriteSER->io_Baud = (ULONG)cnx->devicespeed;
		cnx->TempSER->io_Baud = (ULONG)cnx->devicespeed;
	}

	DoIO((struct IORequest *)cnx->ReadSER);	/* if it didn't work, let the user worry :-) */

#endif

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

void close_ser(struct Connection *cnx)
{
	/* Read pending? YES, abort it */
	if(cnx->aux_stat & AUX_CMD_READ)
	{
		AbortIO((struct IORequest *)cnx->ReadSER);
		WaitIO((struct IORequest *)cnx->ReadSER);
	}
	/* Write pending? YES, wait for it to complete (TODO:LOCKUP possibility?) */
	if(cnx->aux_stat & AUX_CMD_WRITE)
	{
		/* AbortIO((struct IORequest *)cnx->WriteSER); */
		WaitIO((struct IORequest *)cnx->WriteSER);
	}
#if 1
	if(cnx->ReadSER)
	{
		if(cnx->ReadSER->IOSer.io_Device)
			CloseDevice((struct IORequest *)cnx->ReadSER);
		if(cnx->ReadSER->IOSer.io_Message.mn_ReplyPort)
			DeletePort(cnx->ReadSER->IOSer.io_Message.mn_ReplyPort);
		FreeMem(cnx->ReadSER, sizeof(*cnx->ReadSER));
		cnx->ReadSER = NULL;
	}
	if(cnx->WriteSER)
	{
		FreeMem(cnx->WriteSER, sizeof(*cnx->WriteSER));
		cnx->WriteSER = NULL;
	}
	if(cnx->TempSER)
	{
		FreeMem(cnx->TempSER, sizeof(*cnx->TempSER));
		cnx->TempSER = NULL;
	}
#else
	if(cnx->ReadSER)
	{
		if(cnx->ReadSER->IOSer.io_Device)
			CloseDevice((struct IORequest *)cnx->ReadSER);
		if(cnx->ReadSER->IOSer.io_Message.mn_ReplyPort)
			DeletePort(cnx->ReadSER->IOSer.io_Message.mn_ReplyPort);
		FreeMem(cnx->ReadSER, sizeof(*cnx->ReadSER));
		cnx->ReadSER = NULL;
	}
	if(cnx->WriteSER)
	{
		if(cnx->WriteSER->IOSer.io_Device)
			CloseDevice((struct IORequest *)cnx->WriteSER);
		FreeMem(cnx->WriteSER, sizeof(*cnx->WriteSER));
		cnx->WriteSER = NULL;
	}
	if(cnx->TempSER)
	{
		if(cnx->TempSER->IOSer.io_Device)
			CloseDevice((struct IORequest *)cnx->TempSER);
		FreeMem(cnx->TempSER, sizeof(*cnx->TempSER));
		cnx->TempSER = NULL;
	}
#endif

	if(OwnDevUnitBase && (cnx->aux_stat & AUX_USEODU) && (cnx->aux_stat & AUX_LOCKED))
		FreeDevUnit(cnx->devicename,cnx->deviceunit);
}

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

void chk_file(char *name, struct Connection *cnx)
{
	register char *s = name;

	strcpy(cnx->devicename, SERIALNAME);	/* set the defaults */
	cnx->deviceunit = 0;
	cnx->aux_stat = AUX_CRLF;
	cnx->deviceflags = SERF_7WIRE | SERF_RAD_BOOGIE | SERF_XDISABLED;
	cnx->devicespeed = -1;
	cnx->Mode = MODE_RAW;

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

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

	cnx->deviceunit = atoi(s+1);
	strncpy(cnx->devicename, name, (long)(s-name));
	cnx->devicename[(long)(s-name)] = '\0';

	s++;

	while(1)
	{
		while(*s && *s != '/')
			s++;
		if(!*s)
			break;
		++s;
		if(!strncmp(s, "raw", 3))
		{
			cnx->aux_stat &= ~AUX_ECHO;
			cnx->Mode = MODE_RAW;
			s += 3;
		}
		else if(!strncmp(s, "con", 3))
		{
			cnx->aux_stat |= AUX_ECHO;
			cnx->Mode = MODE_CONSOLE;
			s += 3;
		}
		else if(!strncmp(s, "shared", 6))
		{
			cnx->deviceflags |= SERF_SHARED;
			s += 6;
		}
		else if(!strncmp(s, "exclusive", 9))
		{
			cnx->deviceflags &= ~SERF_SHARED;
			s += 9;
		}
		else if(!strncmp(s, "noflow", 6))
		{
			cnx->deviceflags &= ~SERF_7WIRE;
			s += 6;
		}
		else if(!strncmp(s, "useodu", 6))
		{
			cnx->aux_stat |= AUX_USEODU;
			s += 6;
		}
		if(!strncmp(s, "7wire", 5))
		{
			cnx->deviceflags |= SERF_7WIRE;
			s += 5;
		}
		else if(!strncmp(s, "checkcd", 7))
		{
			cnx->aux_stat |= AUX_CHECKCD;
			s += 7;
		}
		else if(!strncmp(s, "speed=", 6))
		{
			cnx->devicespeed = atol(s += 6);
		}
		else if(!strncmp(s, "speed=", 5))
		{
			cnx->devicespeed = 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 */

