home *** CD-ROM | disk | FTP | other *** search
- /*
- * DNET.C
- *
- * DNet device dnet.device
- *
- * Simulates a serial device using dnet.
- *
- * This code is based on Matt Dillon's fms.device. (In fact whatever did not need
- * changing did not get changed).
- *
- * Written by Karl R. Hakimian
- *
- * Bugs & Limits
- * Only one read can be done at a time. A second read queued will abort the first
- * read.
- * SDCMD_BREAK, SDCMD_SETPARAMS are not supported.
- *
- * Modification History
- * 11-24-90 Karl Hakimian Original coding (hacking of fms.device)
- * 12-02-90 Bug fixes support for SDCMD_QUERY added.
- */
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/errors.h>
- #include <exec/memory.h>
- #include <exec/libraries.h>
- #include <devices/serial.h>
- #include <devices/timer.h>
- #include <libraries/dosextens.h>
-
- /*#define DEBUG 1*/
-
- #ifdef DEBUG
- int d_out;
- #endif
-
- long DOSBase = NULL;
-
- #define ABORTED (1<<5)
-
- #define CMD_ABORTREQ (0x7FF0)
- #define CMD_KILLPROC (0x7FF1)
- #define CMD_STARTUP (0x7FF1)
-
- void CoProc();
-
- extern int TagDevOpen();
- extern int TagDevClose();
- extern int TagDevExpunge();
- extern int TagDevBeginIO();
- extern int TagDevAbortIO();
-
- extern void *CreateProc();
- extern void *CreatePort();
- extern void *AllocMem();
- extern void DUMmySeg();
-
- typedef struct Library LIB;
- typedef struct Device DEV;
- typedef struct Process PROC;
- typedef struct MsgPort PORT;
- typedef struct Message MSG;
- typedef struct List LIST;
- typedef struct Node NODE;
- typedef long (*func_ptr)();
-
- typedef struct {
- PORT *Port;
- } NDUnit;
-
- typedef struct {
- LIB Lib;
- char *Host; /* NULL. I will do something with this when Matt does. */
- int Id;
- } NDev;
-
- /* Taken from dnet:amiga/lib/dnetlib.h */
- typedef unsigned char ubyte;
- typedef unsigned short uword;
-
- #define CHANN struct _CHANN
-
- CHANN {
- PORT port; /* receive data, replies */
- PORT *dnetport; /* dnet's master port */
- LIST rdylist; /* ready to be read */
- uword chan; /* channel # for open channels */
- ubyte eof; /* channel remotely closed/eof */
- ubyte filler;
- int qlen; /* allowed write queue size */
- int queued; /* current # packets queued */
- };
-
- #define DNCMD_WRITE 36 /* Write data to a channel */
-
- typedef struct IOStdReq IOSTD;
- /* End of dnet stuff */
-
- typedef struct IOExtSer IOB;
-
- extern char DeviceName[];
- extern char IdString[];
-
- long SysBase = NULL;
- NDev *DevBase = NULL;
- APTR DevSegment = NULL;
-
- NDev *
- Init(seg)
- APTR seg;
- {
- static func_ptr DevVectors[] = {
- (func_ptr)TagDevOpen,
- (func_ptr)TagDevClose,
- (func_ptr)TagDevExpunge,
- NULL,
- (func_ptr)TagDevBeginIO,
- (func_ptr)TagDevAbortIO,
- (func_ptr)-1
- };
- NDev *db;
-
-
- SysBase = *(long *)4;
- DOSBase = OpenLibrary("dos.library",0);
-
- if (DOSBase == NULL)
- return(NULL);
-
- DevBase = db = (NDev *)MakeLibrary((long **)DevVectors,NULL,NULL,sizeof(NDev),NULL);
- db->Lib.lib_Node.ln_Type = NT_DEVICE;
- db->Lib.lib_Node.ln_Name = DeviceName;
- db->Lib.lib_Flags = LIBF_CHANGED|LIBF_SUMUSED;
- db->Lib.lib_Version = 1;
- db->Lib.lib_IdString= (APTR)IdString;
- db->Host = NULL;
- db->Id = 0;
-
- DevSegment = seg;
- AddDevice((DEV *)db);
- #ifdef DEBUG
- d_out = Open("con:0/0/320/200/Debug", 1006);
- #endif
- return(db);
- }
-
- NDev *
- DevOpen(unitnum, iob, flags)
- long unitnum;
- IOB *iob;
- long flags;
- {
- NDUnit *unit;
- IOB siob;
- ULONG port;
- char temp[32];
- int id;
- int i;
-
- #ifdef DEBUG
- Write(d_out,"Open\n",5);
- #endif
- if ((unit = (NDUnit *)AllocMem(sizeof(NDUnit),MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
- iob->IOSer.io_Error = IOERR_OPENFAIL;
- iob->IOSer.io_Device = NULL;
- return(DevBase);
- }
-
- DevBase->Lib.lib_OpenCnt++;
- id = DevBase->Id++;
- /*
- Initialize CoProc process.
- */
- sprintf(temp,"DNet %d",id);
- port = (ULONG)CreateProc(temp, 0, (long)DUMmySeg >> 2, 4096);
- sprintf(temp,"%x",port);
-
- if ((siob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL,0)) == NULL) {
- DevBase->Lib.lib_OpenCnt--;
- FreeMem(unit,sizeof(NDUnit));
- iob->IOSer.io_Error = IOERR_OPENFAIL;
- iob->IOSer.io_Device = NULL;
- return(DevBase);
- }
-
- siob.IOSer.io_Command = CMD_STARTUP;
- siob.IOSer.io_Data = (APTR)unitnum;
- siob.IOSer.io_Length = -1;
- /*
- Lookup for childs port. Timeout in 10 seconds.
- */
- for (i = 0; i < 10 && !(unit->Port = (PORT *)FindPort(temp)); i++)
- Delay(50);
-
- if (unit->Port == NULL) {
- iob->IOSer.io_Error = IOERR_OPENFAIL;
- iob->IOSer.io_Device = NULL;
- DevBase->Lib.lib_OpenCnt--;
- FreeMem(unit,sizeof(NDUnit));
- DeletePort(siob.IOSer.io_Message.mn_ReplyPort);
- return(DevBase);
- }
- /*
- Send startup message.
- */
- PutMsg(unit->Port,&siob.IOSer.io_Message);
- WaitPort(siob.IOSer.io_Message.mn_ReplyPort);
- (void)GetMsg(siob.IOSer.io_Message.mn_ReplyPort);
- DeletePort(siob.IOSer.io_Message.mn_ReplyPort);
- /*
- If there was an error on startup then quit.
- */
- if (siob.IOSer.io_Error) {
- DevBase->Lib.lib_OpenCnt--;
- FreeMem(unit,sizeof(NDUnit));
- iob->IOSer.io_Error = IOERR_OPENFAIL;
- iob->IOSer.io_Device = NULL;
- return(DevBase);
- }
- /*
- Initialize device and io request structure.
- */
- DevBase->Lib.lib_Flags &= ~LIBF_DELEXP;
- iob->IOSer.io_Unit = (struct NDUnit *)unit;
- iob->IOSer.io_Error = 0;
- return(DevBase);
- }
-
- APTR
- DevExpunge()
- {
-
- if (DevSegment == NULL)
- Alert(24, (char *)24);
- if (DevBase->Lib.lib_OpenCnt) {
- DevBase->Lib.lib_Flags |= LIBF_DELEXP;
- return(NULL);
- }
- Remove((NODE *)DevBase);
- CloseLibrary(DOSBase);
- FreeMem((char *)DevBase - DevBase->Lib.lib_NegSize, DevBase->Lib.lib_NegSize + DevBase->Lib.lib_PosSize);
- #ifdef DEBUG
- Close(d_out);
- #endif
- return(DevSegment);
- }
-
- APTR
- DevClose(iob)
- IOB *iob;
- {
- IOB kiob;
- NDUnit *unit;
-
- unit = (NDUnit *)iob->IOSer.io_Unit;
-
- if (unit == NULL || DevBase->Lib.lib_OpenCnt == 0)
- return(NULL);
- /*
- Kill CoProc if it is still there.
- */
- if (unit->Port) {
- kiob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL, 0);
- kiob.IOSer.io_Command = CMD_KILLPROC;
- PutMsg(unit->Port, &kiob.IOSer.io_Message);
- WaitPort(kiob.IOSer.io_Message.mn_ReplyPort);
- DeletePort(kiob.IOSer.io_Message.mn_ReplyPort);
- }
-
- FreeMem(unit,sizeof(NDUnit));
-
- if (DevBase->Lib.lib_OpenCnt && --DevBase->Lib.lib_OpenCnt)
- return(NULL);
-
- if (DevBase->Lib.lib_Flags & LIBF_DELEXP)
- return(DevExpunge());
- /*
- * close down resources
- */
- return(NULL);
- }
-
- void
- DevBeginIO(iob)
- IOB *iob;
- {
- NDUnit *unit;
- IOB *fiob;
-
- unit = (NDUnit *)iob->IOSer.io_Unit;
- #ifdef DEBUG
- Write(d_out,"BeginIO\n",8);
- #endif
- if (unit->Port == NULL) {
- iob->IOSer.io_Error = SerErr_LineErr;
- ReplyMsg(&iob->IOSer.io_Message);
- return;
- }
-
- iob->IOSer.io_Error = 0;
- iob->IOSer.io_Actual = 0;
-
- switch(iob->IOSer.io_Command) {
- case CMD_INVALID:
- iob->IOSer.io_Error = IOERR_NOCMD;
- break;
- case CMD_RESET:
- #ifdef DEBUG
- Write(d_out,"RESET\n",6);
- #endif
- Forbid();
-
- while ((fiob = (IOB *)GetMsg(unit->Port))) {
- fiob->IOSer.io_Flags |= ABORTED;
- ReplyMsg(fiob);
- }
-
- Permit();
- PutMsg(unit->Port, &iob->IOSer.io_Message);
- iob->IOSer.io_Flags &= ~IOF_QUICK;
- iob = NULL;
- break;
- case CMD_READ:
- #ifdef DEBUG
- Write(d_out,"READ\n",5);
- #endif
- PutMsg(unit->Port, &iob->IOSer.io_Message);
- iob->IOSer.io_Flags &= ~IOF_QUICK; /* not quick */
- iob = NULL;
- break;
- case CMD_WRITE:
- #ifdef DEBUG
- Write(d_out,"WRITE\n",6);
- #endif
- PutMsg(unit->Port, &iob->IOSer.io_Message);
- iob->IOSer.io_Flags &= ~IOF_QUICK; /* not quick */
- iob = NULL;
- break;
- case CMD_CLEAR:
- #ifdef DEBUG
- Write(d_out,"CLEAR\n",6);
- #endif
- PutMsg(unit->Port, &iob->IOSer.io_Message);
- iob->IOSer.io_Flags &= ~IOF_QUICK;
- iob = NULL;
- break;
- case CMD_FLUSH:
- #ifdef DEBUG
- Write(d_out,"FLUSH\n",6);
- #endif
- Forbid();
-
- while ((fiob = (IOB *)GetMsg(unit->Port))) {
- fiob->IOSer.io_Flags |= ABORTED;
- ReplyMsg(fiob);
- }
-
- Permit();
- break;
- case SDCMD_QUERY:
- #ifdef DEBUG
- Write(d_out,"QUERY\n",6);
- #endif
- PutMsg(unit->Port, &iob->IOSer.io_Message);
- iob->IOSer.io_Flags &= ~IOF_QUICK;
- iob = NULL;
- break;
- case CMD_STOP:
- case CMD_START:
- case SDCMD_SETPARAMS:
- case SDCMD_BREAK:
- #ifdef DEBUG
- Write(d_out,"OTHER\n",6);
- #endif
- break;
- default:
- #ifdef DEBUG
- Write(d_out,"BAD\n",4);
- #endif
- iob->IOSer.io_Error = IOERR_NOCMD;
- break;
- }
- if (iob) {
- if ((iob->IOSer.io_Flags & IOF_QUICK) == 0)
- ReplyMsg((MSG *)iob);
- }
-
- }
-
- DevAbortIO(iob)
- IOB *iob;
- {
- IOB aiob;
- IOB *riob;
- NDUnit *unit;
- struct List *l;
-
- unit = (NDUnit *)iob->IOSer.io_Unit;
-
- if (unit->Port == NULL) {
- iob->IOSer.io_Flags |= ABORTED;
- ReplyMsg(iob);
- return(IOERR_ABORTED);
- }
-
- l = &unit->Port->mp_MsgList;
- /*
- Search for the request in the message queue.
- */
- #ifdef DEBUG
- Write(d_out,"AbortIO\n",8);
- #endif
- Forbid();
-
- for (riob = (IOB *)l->lh_Head; riob; riob = (IOB *)(((struct Node *)riob)->ln_Succ)) {
- /*
- Request found, remove it.
- */
- if (riob == iob) {
- Remove((struct Node *)riob);
- iob->IOSer.io_Flags |= ABORTED;
- break;
- }
-
- }
-
- Permit();
- /*
- If the request was not found, Tell CoProc to abort.
- */
- if (!riob) {
-
- if ((aiob.IOSer.io_Message.mn_ReplyPort = CreatePort(NULL,0)) == NULL)
- return(NULL);
-
- aiob.IOSer.io_Command = CMD_ABORTREQ;
- aiob.IOSer.io_Data = (APTR)iob;
- aiob.IOSer.io_Length = -1;
- PutMsg(unit->Port, &aiob.IOSer.io_Message);
- WaitPort(aiob.IOSer.io_Message.mn_ReplyPort);
- DeletePort(aiob.IOSer.io_Message.mn_ReplyPort);
- }
- else
- ReplyMsg(riob);
-
- if (iob->IOSer.io_Flags & ABORTED)
- return(IOERR_ABORTED);
-
- return(0);
- }
-
- /*
- * SERVER SIDE (IS A PROCESS)
- */
-
- void
- CoProc()
- {
- IOB *iob;
- IOSTD *dnreq;
- NDUnit *unit;
- PROC *proc;
- PORT *port;
- char notdone = 1;
- int toread;
- int haveread;
- int read;
- int data_ready = 0;
- IOB *riob=NULL;
- char pname[32];
- int Chan;
- int cmask;
- int dmask;
- int sig;
- #ifdef DEBUG
- char buf[256];
- #endif
- /*
- Create command message port.
- */
- proc = (PROC *)FindTask(NULL);
- sprintf(pname,"%x",&(proc->pr_MsgPort));
-
- if ((port = CreatePort(pname,0)) == NULL) {
- return;
- }
- /*
- Wait for startup message.
- */
- (void)Wait(1 << port->mp_SigBit);
-
- iob = (IOB *)GetMsg(port);
-
- if (iob->IOSer.io_Command != CMD_STARTUP || (Chan = DOpen(DevBase->Host,iob->IOSer.io_Data)) == NULL) {
- iob->IOSer.io_Error = IOERR_OPENFAIL;
- ReplyMsg(&iob->IOSer.io_Message);
- DeletePort(port);
- return;
- }
-
- iob->IOSer.io_Error = 0;
- ReplyMsg(&iob->IOSer.io_Message);
-
- DQueue(Chan,128);
- dmask = 1 << ((PORT *)Chan)->mp_SigBit;
- cmask = 1 << port->mp_SigBit;
- #ifdef DEBUG
- sprintf(buf,"dmask = %xx, cmask = %xx\n",dmask,cmask);
- Write(d_out,buf,strlen(buf));
- #endif
-
- while (notdone) {
- sig = Wait(cmask|dmask);
-
- if (sig&cmask) {
-
- while (iob = (IOB *)GetMsg(port)) {
- unit = (NDUnit *)iob->IOSer.io_Unit;
-
- switch(iob->IOSer.io_Command) {
- case CMD_ABORTREQ:
- #ifdef DEBUG
- Write(d_out,"ABORT\n",6);
- #endif
-
- if (iob->IOSer.io_Data == (APTR)riob) {
- riob->IOSer.io_Flags |= ABORTED;
- ReplyMsg(&riob->IOSer.io_Message);
- riob = NULL;
- }
-
- break;
- case CMD_RESET:
- #ifdef DEBUG
- Write(d_out,"RESET\n",6);
- #endif
-
- if (riob) {
- riob->IOSer.io_Flags |= ABORTED;
- ReplyMsg(&riob->IOSer.io_Message);
- }
- /*
- We want to fall through to clear.
- */
- case CMD_CLEAR:
- #ifdef DEBUG
- Write(d_out,"CLEAR\n",6);
- #endif
- /*
- Remove all data from the read buffer.
- */
- while (DNRead(Chan,(char *)&data_ready,1))
- ;
-
- data_ready = 0;
- break;
- case SDCMD_QUERY:
- #ifdef DEBUG
- Write(d_out,"QUERY\n",5);
- #endif
- iob->io_Status = 0xf8;
- Forbid();
-
- for (dnreq = (IOSTD *)((CHANN *)Chan)->rdylist.lh_Head; dnreq; dnreq = (IOSTD *)((struct Node *)dnreq)->ln_Succ) {
-
- if (dnreq->io_Command == DNCMD_WRITE)
- iob->IOSer.io_Actual += dnreq->io_Length - dnreq->io_Actual;
-
- }
-
- for (dnreq = (IOSTD *)((CHANN *)Chan)->port.mp_MsgList.lh_Head; dnreq; dnreq = (IOSTD *)((struct Node *)dnreq)->ln_Succ) {
-
- if (dnreq->io_Command == DNCMD_WRITE)
- iob->IOSer.io_Actual += dnreq->io_Length - dnreq->io_Actual;
-
- }
-
- Permit();
- break;
- case CMD_KILLPROC:
- #ifdef DEBUG
- Write(d_out,"KILL\n",5);
- #endif
- goto exit_proc;
- break;
- case CMD_READ:
- #ifdef DEBUG
- Write(d_out,"READ\n",5);
- #endif
- /*
- Currently only allows one read at a time. If a read request comes in while one
- is still pending then abort the first read.
- */
- if (riob) {
- riob->IOSer.io_Error = SerErr_LineErr;
- ReplyMsg(&riob->IOSer.io_Message);
- riob = NULL;
- }
-
- toread = iob->IOSer.io_Length;
- haveread = 0;
- riob = iob;
- iob = NULL;
- break;
- case CMD_WRITE:
- #ifdef DEBUG
- Write(d_out,"WRITE\n",6);
- #endif
-
- if (iob->IOSer.io_Length >= 0)
- iob->IOSer.io_Actual = DWrite(Chan, (char *)iob->IOSer.io_Data, iob->IOSer.io_Length);
- else if (iob->IOSer.io_Length == -1)
- iob->IOSer.io_Actual = DWrite(Chan, (char *)iob->IOSer.io_Data, strlen((char *)iob->IOSer.io_Data));
- else
- iob->IOSer.io_Actual = iob->IOSer.io_Length;
-
- if (iob->IOSer.io_Actual < 0) {
- iob->IOSer.io_Error = SerErr_LineErr;
- goto exit_proc;
- }
-
- break;
- default:
- iob->IOSer.io_Error = SerErr_LineErr;
- break;
- }
-
- if (iob)
- ReplyMsg(&iob->IOSer.io_Message);
-
- }
-
- }
- /*
- Do the read if there is data and a pending read request.
- */
- if (((sig&dmask) || data_ready) && riob) {
-
- if (toread == -1) {
-
- while (riob && (read = DNRead(Chan,(char *)&riob->IOSer.io_Data[haveread],1))) {
- if ((char *)&riob->IOSer.io_Data[haveread] == '\0') {
- riob->IOSer.io_Actual = haveread;
- ReplyMsg(&riob->IOSer.io_Message);
- riob = NULL;
- toread = haveread = 0;
- }
-
- haveread++;
- }
-
- continue;
- }
-
- read = DNRead(Chan, (char *)&riob->IOSer.io_Data[haveread], toread);
-
- if (read < 0) {
- riob->IOSer.io_Error = SerErr_LineErr;
- ReplyMsg(&riob->IOSer.io_Message);
- iob = NULL;
- goto exit_proc;
- }
- else if (read == 0)
- data_ready = 0;
- else {
- data_ready = 1; /* data_read is true until no data is left. */
- haveread += read;
- toread -= haveread;
- }
-
- if (toread <= 0) {
- riob->IOSer.io_Actual = haveread;
- ReplyMsg(&riob->IOSer.io_Message);
- riob = NULL;
- toread = haveread = 0;
- }
-
- }
- else if (sig&dmask) /* There is data ready so record rember it. */
- data_ready = 1;
-
- }
- /* fall through to exit */
-
- Forbid(); /* Forbid before exiting. */
- return;
-
- exit_proc:
- #ifdef DEBUG
- Write(d_out,"exiting\n",8);
- #endif
-
- if (riob) {
- riob->IOSer.io_Error = SerErr_LineErr;
- ReplyMsg(&riob->IOSer.io_Message);
- }
-
- DClose(Chan);
- #ifdef DEBUG
- Write(d_out,"DNET closed\n",12);
- #endif
-
- while (riob = (IOB *)GetMsg(port)) {
- riob->IOSer.io_Error = SerErr_LineErr;
- riob->IOSer.io_Flags |= ABORTED;
- ReplyMsg(&riob->IOSer.io_Message);
- }
-
- DeletePort(port);
- unit->Port = NULL;
- #ifdef DEBUG
- Write(d_out,"Port gone\n",10);
- #endif
- Forbid(); /* Forbid before exiting. */
-
- if (iob)
- ReplyMsg(&iob->IOSer.io_Message);
-
- }
-