home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- *
- * Aux Driver V1.0 (c)CopyRight 1987, Steve Drew. All Rights Reserved.
- *
- * Aux-Handler Ver. 1.0 1-May-1987
- *
- * Steve Drew
- * 52-Castledale Cres. N.E.
- * Calgary, Ab. Canada.
- *
- * |You may freely distribute this source as long as |
- * |the Copyright notice is left intact. |
- ***************************************************************************/
-
-
- #include <devices/serial.h>
- #include <devices/timer.h>
-
-
- typedef unsigned char u_char;
-
- #undef BADDR
- #define BADDR(x) ((APTR)((long)x << 2))
-
- #define ACTION_FINDINPUT 1005L
- #define ACTION_FINDOUTPUT 1006L
- #define ACTION_END 1007L
- #define ACTION_SCREEN_MODE 994L
-
- #define DOS_FALSE 0L
- #define DOS_TRUE -1L
-
- #define AUX_ECHO 1
- #define AUX_CRLF 2
- #define AUX_RAW 4
- #define AUX_RPEND 8
- #define AUX_WAIT_FOR 16
- #define AUX_TYPEAHEAD_FULL 32
- #define AUXBUFSIZE 256 /* Same as CON: handler */
- #define MAXLINESIZE 254 /* save two for \n'\0' */
-
-
- #define MYPORT_SIG (1L << myport->mp_SigBit)
- #define READSER_SIG (1L << ReadSER->IOSer.io_Message.mn_ReplyPort->mp_SigBit)
- #define TIMER_SIG (1L << Timer_Port->mp_SigBit)
-
- /* extern long AbsExecBase; */
-
- /* My Globals */
-
-
- struct IOExtSer *ReadSER;
- struct IOExtSer *WriteSER;
- struct timerequest *Timer;
- struct MsgPort *Timer_Port;
- struct Task *reader;
- long SysBase;
- int aux_stat,
- aux_avail,
- in_len;
- u_char in_c;
-
- _main()
- {
-
- extern void returnpkt(); /* sends back the packet */
- extern void returnpktplain(); /* use args in Res1 */
- extern struct DosPacket *taskwait();
-
- char *version = "Ver 1.0 (c) Steve Drew 1987";
- struct Process *myproc; /* my process */
- struct DosPacket *mypkt; /* a pointer to the dos packet */
- struct DosPacket *rdpkt;
- struct DeviceNode *mynode; /* our device node (parmpkt Arg3) */
- struct FileHandle *fh; /* a pointer to our file handle */
- struct MsgPort *myport;
- long run = TRUE; /* handler main loop flag */
- u_char *ptr; /* ptr for name translation */
- char *name,*s; /* ptr to name for open */
- int aux_open = 0; /* aux open count */
- char auxbuf[AUXBUFSIZE];/* Our type ahead buffer */
- long signals; /* signals that occurred in Wait */
-
-
- /* Initializing the handler */
-
- myproc = (struct Process *)FindTask(0L);
- mypkt = taskwait(myproc); /* Wait for my startup message */
-
- /* I 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);
-
- in_len = aux_avail = aux_stat = 0;
- reader = (struct Task *) 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) {
- WaitIO(Timer);
- aux_stat &= ~AUX_WAIT_FOR;
- rdpkt->dp_Res1 = DOS_FALSE;
- returnpktplain(rdpkt,myproc);
- }
- if ((signals & READSER_SIG) && CheckIO(ReadSER)) {
- read_ser(auxbuf);
- chk_pend(auxbuf,rdpkt,myproc);
- }
- if (signals & MYPORT_SIG) {
- mypkt = taskwait(myproc);
- }
- else /* no new dospackets */
- continue;
- }
- else /* only port at the moment is myport */
- mypkt = taskwait(myproc);
-
- switch(mypkt->dp_Type) { /* find what action to perform */
-
- case ACTION_FINDINPUT:
-
- if (reader) { /* Have I already got a someone reading */
- returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
- break;
- }
-
- case ACTION_FINDOUTPUT:
-
- /*
- I allow for multiple writers. But doesn't make sense
- to allow for mutilple readers.
- */
- if (!aux_open) { /* first time here we open the devices */
- if ((aux_open = open_stuff()) == 0) {
- returnpkt(mypkt, myproc, DOS_FALSE, ERROR_OBJECT_IN_USE);
- break;
- }
- }
- else
- aux_open++;
-
- /* get file name and Upper case it */
- ptr = (u_char *)BADDR(mypkt->dp_Arg3);
- name = AllocMem((long)*ptr + 1, MEMF_PUBLIC);
- movmem(ptr+1, name, *ptr);
- name[*ptr] = '\0';
- for (s = name; *s; ++s) *s = toupper(*s);
-
-
- /*
- This is a Hack to allow a bail out of a NEWCLI
- that is using the AUX. By doing say an echo >AUX:ENDCLI
- from another process the reader (being the NEWCLI)
- will be sent a ENDCLI command.
- */
-
- if (!strcmp(name,"AUX:ENDCLI") && (aux_stat & AUX_RPEND)) {
- strcpy(rdpkt->dp_Arg2,"ENDCLI\n");
- rdpkt->dp_Res1 = 7L;
- returnpktplain(rdpkt, myproc);
- aux_stat &= ~AUX_RPEND;
- }
- else
- chk_params(name);
-
- FreeMem(name, (long)*ptr +1);
- 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;
- aux_stat |= AUX_RPEND;
- chk_pend(auxbuf,rdpkt,myproc);
-
- break;
-
- case ACTION_WRITE:
-
- write_ser(mypkt->dp_Arg2,(int)mypkt->dp_Arg3);
- mypkt->dp_Res1 = mypkt->dp_Arg3; /* tell em we wrote them all */
-
- returnpktplain(mypkt, myproc);
- break;
-
- case ACTION_WAIT_CHAR:
-
- /* just queue up to wait for data */
-
- rdpkt = mypkt;
- aux_stat |= AUX_WAIT_FOR;
- Timer->tr_time.tv_secs = 0L;
- Timer->tr_time.tv_micro = rdpkt->dp_Arg1;
- SendIO(Timer);
- chk_pend(auxbuf,rdpkt,myproc);
- break;
-
- case ACTION_SCREEN_MODE:
-
- if (mypkt->dp_Arg1) {
- aux_stat |= AUX_RAW;
- aux_stat &= ~AUX_ECHO;
- }
- else {
- aux_stat &= ~AUX_RAW;
- aux_stat |= AUX_ECHO;
- }
- chk_pend();
- returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
- break;
-
- case ACTION_END:
-
- if (--aux_open == 0) {
- run = 0;
- close_timer();
- close_ser();
- }
- if (mypkt->dp_Arg1 == (long)reader) reader = (struct Task *) 0;
- returnpkt(mypkt, myproc, DOS_TRUE, mypkt->dp_Res2);
- break;
-
- default:
-
- returnpkt(mypkt, myproc, DOS_FALSE, ERROR_ACTION_NOT_KNOWN);
- break;
- }
- } /* end while */
- mynode->dn_Task = FALSE;
- }
-
-
- /*
- Allows some flexibilty to control the port.
- Can dynamically change CRLF translation,
- Echo or RAW mode on/off.
- */
- chk_params(str)
- char *str;
- {
- char *ptr, *s;
- int param, i=1;
-
- if (strncmp(str,"AUX:SET/",8)) return;
- ptr = str + 8;
- while(i) {
- for (s = ptr; *ptr && *ptr != '/'; ++ptr);
- if (*ptr == '\0') i = 0;
- *ptr = '\0';
- str = s+2;
- if (ptr > str) {
- switch (*s) {
- case 'E':
- param = AUX_ECHO;
- break;
- case 'C':
- param = AUX_CRLF;
- break;
- case 'R':
- param = AUX_RAW;
- break;
- default:
- param = 0;
- break;
- }
- if (*str == 'O') {
- if (*(str+1) == 'N') aux_stat |= param;
- else
- if (*(str+1) == 'F') aux_stat &= ~param;
- }
- }
- ++ptr;
- }
- }
-
-
- /*
- Start a asynchronous Read request
- */
- set_read()
- {
- /* set up for a read */
- ReadSER->IOSer.io_Length = 1L;
- ReadSER->IOSer.io_Command = CMD_READ;
- ReadSER->IOSer.io_Data = (APTR) &in_c;
- SendIO(ReadSER);
- }
-
- /*
- Check our buf to see if we have a line to return yet. Or if raw mode
- give 'em all we got.
- */
- chk_pend(buf,pkt,proc)
- char *buf;
- struct DosPacket *pkt;
- struct Process *proc;
- {
- extern void returnpktplain();
- char *p;
- int i=0;
-
- if ((in_len && (aux_stat & AUX_RAW)) || aux_avail) {
- if (aux_stat & AUX_WAIT_FOR) {
- aux_stat &= ~AUX_WAIT_FOR; /* clear the wait_for */
- pkt->dp_Res1 = DOS_TRUE;
- AbortIO(Timer);
- WaitIO(Timer);
- Wait (1L << Timer_Port->mp_SigBit);
- returnpktplain(pkt,proc);
- }
- else if (aux_stat & AUX_RPEND) {
- aux_stat &= ~AUX_RPEND; /* clear the pending read */
- if (aux_stat & AUX_RAW) {
- aux_avail = 0; /* since we're sending all */
- }
- else
- --aux_avail;
-
- /* if in_len is zero, then aux_avail must of been
- set up to force us here to reply with Res1 = 0;
- thus actually returning an EOF.
- */
- if (in_len) {
- for (i = 1,p = (char *) pkt->dp_Arg2;
- ((p[i-1] = buf[i-1]) != 10 || (aux_stat & AUX_RAW)) &&
- i < pkt->dp_Arg3 && i < in_len; ++i) ;
-
- /* reader asked for less than 256 chars but no cr
- was found. If not in raw mode then bump avail back
- up since we still have the remaining CR terminated
- line in buf[].
- */
- if (p[i-1] != 10 && !(aux_stat & AUX_RAW)) {
- ++aux_avail;
- }
- }
- in_len -= i;
- movmem(buf+i,buf,in_len);
- if (in_len < MAXLINESIZE - 1 && (aux_stat & AUX_TYPEAHEAD_FULL)) {
- aux_stat &= ~AUX_TYPEAHEAD_FULL;
- set_read(); /* start waiting for reads again */
- }
- pkt->dp_Res1 = (long)i;
- returnpktplain(pkt,proc);
- }
- }
- }
-
- /*
- Only called here if there really is a character waiting to be read.
- */
- read_ser(buf)
- char *buf;
- {
- char c;
-
- WaitIO(ReadSER);
- c = in_c;
-
- if (c == 3) { /* ^C typed so immediately send the signal */
- if (!(aux_stat & AUX_RAW))
- c = 0;
- if (reader)
- Signal(reader,SIGBREAKF_CTRL_C);
- }
-
- if (!(aux_stat & AUX_RAW)) switch(c) {
- case 4: /* ^D, send the signal if not in raw mode */
- c = 0;
- if (reader)
- 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 = 10;
- break;
- case 10: /* ignore these */
- if (aux_stat & AUX_CRLF) c = 0;
- break;
- case 8: /* BS */
- case 127: /* DEL */
- if (in_len && buf[in_len-1] != 10) {
- --in_len;
- write_ser("\010 \010",3);
- }
- c = 0;
- break;
- case 24: /* ^X */
- case 21: /* ^U */
- while(in_len && buf[in_len-1] != 10) {
- --in_len;
- write_ser("\010 \010",3);
- }
- c = 0;
- break;
- case 27: /* <ESC> */
- c = 0;
- default:
- break;
- }
- if (aux_stat & AUX_ECHO) {
- if ((aux_stat & AUX_CRLF) && c == 10) putc_ser(13);
- putc_ser(c);
- }
- if (c == 10) ++aux_avail; /* always done when CR received */
-
- /* If our buffer is full then ignore any further input. (it
- will stack up in the serial.device buffer) If our buffer
- contains no CR's (unterminated) then add a newline. At
- this point the CON: driver would wait for the user to type
- a return while ignoring any other key strokes.
- In raw mode the buffer CAN be full and unterminated. Since
- when ever the reader asks for data we give him what ever
- we have so far.
- */
- if (in_len >= MAXLINESIZE) {
- aux_stat |= AUX_TYPEAHEAD_FULL;
- if (!aux_avail && !(aux_stat & AUX_RAW)) {
- ++aux_avail;
- buf[in_len++] = 10;
- }
- }
- else
- set_read();
-
- if (c) buf[in_len++] = c;
- }
-
- /*
- Write 'em out one by one converting to CR LF if enabled.
- */
- write_ser(buf,len)
- char *buf;
- int len;
- {
- int i=0;
- char c;
-
- for (i=0; i<len; i++) {
- c = buf[i];
- if (c == 10 && (aux_stat & AUX_CRLF)) putc_ser(13);
- putc_ser(c);
- }
- }
-
- /*
- Perform Synchronous write.
- */
- putc_ser(c)
- char c;
- {
- if (c) {
- WriteSER->IOSer.io_Length = 1L;
- WriteSER->IOSer.io_Data = (APTR) &c;
- DoIO(WriteSER);
- }
- }
-
- open_stuff()
- {
- BYTE *c,*b;
- int i;
-
- aux_stat = AUX_ECHO | AUX_CRLF; /* set the default */
- if ((ReadSER = (struct IOExtSer *)
- AllocMem((long)sizeof(*ReadSER),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
- return(0);
- if ((WriteSER = (struct IOExtSer *)
- AllocMem((long)sizeof(*WriteSER),MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
- FreeMem(ReadSER,(long)sizeof(*ReadSER));
- return(0);
- }
- ReadSER->IOSer.io_Message.mn_ReplyPort = CreatePort(0,0);
- if (OpenDevice(SERIALNAME,NULL,ReadSER,NULL)) {
- DeletePort(ReadSER->IOSer.io_Message.mn_ReplyPort);
- FreeMem(WriteSER,(long)sizeof(*WriteSER));
- FreeMem(ReadSER,(long)sizeof(*ReadSER));
- return(0);
- }
-
- b = (BYTE *)ReadSER;
- c = (BYTE *)WriteSER;
- for (i=0;i<sizeof(struct IOExtSer);i++) *c++ = *b++;
-
- WriteSER->IOSer.io_Message.mn_ReplyPort = CreatePort(0,0);
- WriteSER->IOSer.io_Command = CMD_WRITE;
-
- /* Open Timer.device */
- if (Timer_Port = CreatePort (NULL, NULL)) {
- if ((Timer = CreateExtIO (Timer_Port, (long) sizeof (*Timer)))) {
- if (!(OpenDevice (TIMERNAME, UNIT_VBLANK, Timer, 0L))) {
- Timer->tr_node.io_Command = TR_ADDREQUEST;
- Timer->tr_node.io_Flags = 0;
- Timer->tr_node.io_Error = 0;
- set_read();
- return(1);
- }
- }
- }
- Timer->tr_node.io_Device = 0;
- close_timer();
- close_ser();
- return(0);
-
- }
-
- close_ser()
- {
- if (!(aux_stat & AUX_TYPEAHEAD_FULL)) {
- AbortIO(ReadSER);
- WaitIO(ReadSER);
- }
- DeletePort(WriteSER->IOSer.io_Message.mn_ReplyPort);
- FreeMem(WriteSER,(long)sizeof(*WriteSER));
- CloseDevice(ReadSER);
- DeletePort(ReadSER->IOSer.io_Message.mn_ReplyPort);
- FreeMem(ReadSER,(long)sizeof(*ReadSER));
- }
-
- close_timer()
- {
-
- if (Timer) {
- if (Timer->tr_node.io_Device)
- CloseDevice (Timer);
- DeleteExtIO (Timer, (long) sizeof (*Timer));
- }
- if (Timer_Port) DeletePort(Timer_Port);
-
- }
-
-
-