home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * PIPE: device driver.
- *
- * Usage:
- * The writer opens PIPE:somename and begins writing to it. The reader
- * opens PIPE:samename and begins reading from it. It doesn't matter
- * who opens PIPE:somename first. Note that if the writer opens the
- * handle first, writes <BUFSIZE bytes, then closes, the Close() will
- * not return until a reader has openned the same pipe.
- *
- * -Only two opens can be made on a specific pipe
- * -One of the opens must always write while the other must always
- * read.
- *
- * If the reader closed, any further writes will return an error
- * If the writer closed, any further reads (after the buffer empties)
- * will return 0.
- *
- * NOTE: Like the filesystem DOS device, I assume that no more than one
- * request for a specific file handle will be queued at a time. This makes
- * things a lot easier for me.
- *
- *
- */
-
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/ports.h>
- #include <exec/libraries.h>
- #include <exec/devices.h>
- #include <exec/io.h>
- #include <exec/memory.h>
- #include <devices/console.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <libraries/filehandler.h>
-
- typedef struct DosPacket DOSPACKET;
- typedef struct Process PROC;
- typedef struct DeviceNode DEVNODE;
- typedef struct FileHandle FH;
- typedef unsigned char u_char;
-
- #define BUFSIZE 4096
-
- #undef BADDR
- #define BADDR(x) ((APTR)((long)x << 2))
-
- #define ACTION_FIND_INPUT 1005L
- #define ACTION_FIND_OUTPUT 1006L
- #define ACTION_END 1007L
-
- #define DOS_FALSE 0
- #define DOS_TRUE -1
-
- #define ST_EOF 0x01 /* Handle has been closed */
- #define ST_WPEND 0x04 /* pending packet is a write */
- #define ST_RPEND 0x08 /* pending packet is a read */
- #define ST_CPEND 0x10 /* close pending (writer) */
-
- #define OC_FIRST 1 /* first open, needs to be another */
- #define OC_BOTH 2 /* both reader and writer open */
- #define OC_LAST 3 /* one closed, one remaining */
- #define OC_WAITSECOND 4 /* first open was closed before second was openned */
-
-
- extern long AbsExecBase;
- extern DOSPACKET *taskwait();
- extern char *AllocMem();
- long SysBase;
-
- typedef struct _PIPE {
- struct _PIPE *next, **prev;
- DOSPACKET *pkt; /* Current pending packet, if any */
- char buf[BUFSIZE]; /* Output Buffer */
- char *name; /* name (allocated strlen(name)+1) */
- short s, e, l; /* FIFO start, end, size */
- char state; /* Current state */
- char openstate;
- } PIPE;
-
-
- _main()
- {
- PROC *myproc; /* my process */
- DOSPACKET *mypkt; /* a pointer to the dos packet sent */
- BSTR parmdevname; /* pointer to device name in parmpkt Arg1 */
- long parmextra; /* extra info passed in parmpkt Arg2 */
- DEVNODE *mynode; /* our device node passed in parmpkt Arg3 */
- FH *fh; /* a pointer to our file handle */
- PIPE *pipe; /* current PIPE handle */
- PIPE *Pipe = NULL;/* linked list base for all pipes */
- char *str;
- u_char *ptr;
- long run = TRUE; /* handler main loop flag */
- int ret; /* nominal packet return value */
- int totalcnt = 0;/* total # active pipes */
-
- SysBase = AbsExecBase;
-
- myproc = (PROC *)FindTask(0L); /* find myself */
- mypkt = taskwait(myproc); /* Wait for startup message */
- parmdevname = (BSTR)mypkt->dp_Arg1; /* BSTR name passed to handler */
- parmextra = mypkt->dp_Arg2; /* Extra Info passed */
- mynode = (DEVNODE *)BADDR(mypkt->dp_Arg3); /* ptr to device node */
-
- /* if taskid NOT installed, every ref creates new */
- /* code must be reentrant */
-
- mynode->dn_Task = &myproc->pr_MsgPort;
- returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
-
- while(run) {
- mypkt = taskwait(myproc);
- ret = DOS_TRUE;
- pipe = (PIPE *)mypkt->dp_Arg1;
-
- switch(mypkt->dp_Type) {
- case ACTION_FIND_INPUT:
- case ACTION_FIND_OUTPUT:
- fh = (FH *)BADDR(mypkt->dp_Arg1); /* File handle */
- ptr = (u_char *)BADDR(mypkt->dp_Arg3); /* File name */
- str = AllocMem(*ptr + 1, 0);
- if (str == NULL) {
- ret = DOS_FALSE;
- goto opfail;
- }
- bmov(ptr+1, str, *ptr);
- str[*ptr] = 0;
- for (pipe = Pipe; pipe; pipe = pipe->next) {
- if (strcmp(pipe->name, str) == 0) {
- FreeMem(str, *ptr + 1);
- goto openok;
- }
- }
- pipe = (PIPE *)AllocMem(sizeof(PIPE), 0);
- if (pipe == NULL) {
- ret = DOS_FALSE;
- FreeMem(str, *ptr + 1);
- goto opfail;
- }
- ++totalcnt;
-
- bzero(pipe, sizeof(*pipe));
- pipe->l = BUFSIZE;
- pipe->name = str;
- if (Pipe)
- Pipe->prev = &pipe->next;
- pipe->next = Pipe;
- pipe->prev = &Pipe;
- Pipe = pipe;
- openok:
- switch(pipe->openstate) {
- case 0:
- pipe->openstate = OC_FIRST;
- break;
- case OC_FIRST:
- pipe->openstate = OC_BOTH;
- break;
- case OC_WAITSECOND:
- pipe->openstate = OC_LAST;
- pipe->state &= ~ST_CPEND;
- returnpkt(pipe->pkt, myproc, DOS_TRUE, pipe->pkt->dp_Res2);
- break;
- case OC_BOTH:
- case OC_LAST:
- ret = DOS_FALSE; /* more than 2 opens */
- goto opfail;
- }
- fh->fh_Arg1 = (long)pipe;
- fh->fh_Port = (struct MsgPort *)DOS_TRUE;
- opfail:
- returnpkt(mypkt, myproc, ret, mypkt->dp_Res2);
- break;
- case ACTION_END: /* If pending read, return pend bytes read
- * If pending write, return pend bytes written
- * return pending message, if any
- */
- switch(pipe->openstate) {
- case OC_FIRST:
- pipe->openstate = OC_WAITSECOND;
- break;
- case OC_BOTH:
- pipe->openstate = OC_LAST;
- break;
- case OC_LAST:
- pipe->openstate = 0;
- break;
- }
-
- pipe->state |= ST_EOF;
-
- if (pipe->openstate == OC_WAITSECOND) {
- pipe->pkt = mypkt;
- pipe->state |= ST_CPEND;
- break;
- }
-
- if (pipe->state & (ST_RPEND|ST_WPEND)) {
- returnpktplain(pipe->pkt, myproc);
- pipe->state &= ~(ST_RPEND|ST_WPEND);
- }
- if (pipe->openstate == 0) {
- FreeMem(pipe->name, strlen(pipe->name)+1);
- *pipe->prev = pipe->next;
- if (pipe->next)
- pipe->next->prev = pipe->prev;
- FreeMem(pipe, sizeof(*pipe));
- --totalcnt;
- if (totalcnt == 0)
- run = 0;
- }
- returnpkt(mypkt, myproc, ret, mypkt->dp_Res2);
- break;
- case ACTION_READ: /* Take chars from buffer. If buffer empty
- * and read not satisfied, check for pending
- * write and take bytes from it's buffer.
- * When done, must check to see if buffer will
- * hold ALL of pending write.
- * When done, if read still is not satisfied,
- * make it pending.
- */
-
- mypkt->dp_Res1 = 0;
-
- /*
- * Load from buffer until empty or read fulfilled
- */
-
- while (pipe->s != pipe->e && mypkt->dp_Res1 != mypkt->dp_Arg3) {
- int avail = (pipe->s < pipe->e) ? pipe->e - pipe->s :
- pipe->l - pipe->s;
- int bytes = mypkt->dp_Arg3 - mypkt->dp_Res1;
- if (bytes < avail)
- avail = bytes;
- bmov(pipe->buf+pipe->s, mypkt->dp_Arg2+mypkt->dp_Res1,avail);
- pipe->s += avail;
- mypkt->dp_Res1 += avail;
- if (pipe->s == pipe->l)
- pipe->s = 0;
- }
-
- /*
- * If write packet was pending, the read will either exhaust
- * the write and possibly become pending, or not exhaust the
- * write and be returned.
- */
-
- if (mypkt->dp_Res1 != mypkt->dp_Arg3 && (pipe->state & ST_WPEND)) {
- int bytes = mypkt->dp_Arg3 - mypkt->dp_Res1;
- int avail = pipe->pkt->dp_Arg3 - pipe->pkt->dp_Res1;
- if (bytes > avail)
- bytes = avail;
- bmov(pipe->pkt->dp_Arg2 + pipe->pkt->dp_Res1, mypkt->dp_Arg2 + mypkt->dp_Res1, bytes);
- mypkt->dp_Res1 += bytes;
- pipe->pkt->dp_Res1 += bytes;
- if (pipe->pkt->dp_Res1 == pipe->pkt->dp_Arg3) {
- returnpktplain(pipe->pkt, myproc);
- pipe->state &= ~ST_WPEND;
- }
- }
-
- /* If read packet is made pending, buffer is always empty */
-
- if (mypkt->dp_Res1 != mypkt->dp_Arg3 && !(pipe->state&ST_EOF)) {
- if (pipe->state & (ST_RPEND|ST_WPEND|ST_CPEND)) {
- returnpkt(pipe->pkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
- pipe->state &= ~(ST_RPEND|ST_WPEND|ST_CPEND);
- }
- pipe->pkt = mypkt;
- pipe->state |= ST_RPEND;
- } else {
- returnpktplain(mypkt, myproc);
- }
- break;
- case ACTION_WRITE: /*
- * If pending read then buffer is empty, place
- * chars directly into pending read. If pending
- * write, error.
- * If nothing pending and write buffer not big
- * enough, make the write pend without filling
- * the buffer. Otherwise, move write data into
- * the buffer and return the packet.
- */
-
- mypkt->dp_Res1 = 0;
-
- if (pipe->state & ST_EOF) {
- returnpkt(mypkt, myproc, DOS_FALSE, ERROR_SEEK_ERROR);
- break;
- }
- if (pipe->state & ST_RPEND) { /* write->read */
- int avail = mypkt->dp_Arg3 - mypkt->dp_Res1;
- int bytes = pipe->pkt->dp_Arg3 - pipe->pkt->dp_Res1;
- if (avail < bytes)
- bytes = avail;
- bmov(mypkt->dp_Arg2+mypkt->dp_Res1, pipe->pkt->dp_Arg2+pipe->pkt->dp_Res1, bytes);
- mypkt->dp_Res1 += bytes;
- pipe->pkt->dp_Res1 += bytes;
- if (pipe->pkt->dp_Res1 == pipe->pkt->dp_Arg3) {
- returnpktplain(pipe->pkt, myproc);
- pipe->state &= ~ST_RPEND;
- }
- }
-
- /* write into buffer */
-
- while (mypkt->dp_Res1 != mypkt->dp_Arg3 && pipe->s != ((pipe->e+1)%pipe->l)) {
- int avail = mypkt->dp_Arg3 - mypkt->dp_Res1;
- int bytes;
- if (pipe->e < pipe->s)
- bytes = pipe->s - pipe->e - 1;
- else
- bytes = pipe->l - pipe->e - (pipe->s == 0);
- if (avail < bytes)
- bytes = avail;
- bmov(mypkt->dp_Arg2 + mypkt->dp_Res1, pipe->buf + pipe->e, bytes);
- pipe->e += bytes;
- mypkt->dp_Res1 += bytes;
- if (pipe->e == pipe->l)
- pipe->e = 0;
- }
-
- if (mypkt->dp_Res1 != mypkt->dp_Arg3) {
- if (pipe->state & (ST_RPEND|ST_WPEND|ST_CPEND)) {
- returnpkt(pipe->pkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
- pipe->state &= ~(ST_RPEND|ST_WPEND|ST_CPEND);
- }
- pipe->pkt = mypkt;
- pipe->state |= ST_WPEND;
- } else {
- returnpktplain(mypkt, myproc);
- }
- break;
- default:
- returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
- break;
- }
- }
- mynode->dn_Task = FALSE;
-
- /* we are a process "so we fall off the end of the world" */
- /* MUST fall through */
- }
-
-
-
-