/* * Modifications to existing pc.c module are -- * * Copyright (c) 1987 * Louis A. Mamakos * * This work, or any derivations thereof may be used for non-commercial * purposes only. So there. */ /* OS- and machine-dependent stuff for the Commodore-Amiga 1000 */ #define AMIGAVERSION "3" #include #include /* for Manx Aztec C, get func returns */ #include #include #include #include #include #include #include #include #include #include #include #include #include "machdep.h" #include "amiga.h" #include "mbuf.h" #include "internet.h" #include "iface.h" #include "cmdparse.h" #include "slip.h" #include "timer.h" #include "netuser.h" #include "ip.h" #include "tcp.h" #ifdef TRACE #include "trace.h" #endif static char *copyright_notice[2] = { "AMIGA port of KA9Q TCP/IP (C) Copyright 1987 Louis A. Mamakos\r\n", "for non-commercial, non-profic use only\r\n"}; struct asy asy[ASY_MAX]; void *malloc(); void setiss(); /* Interface list header */ struct interface *ifaces; struct IntuitionBase *IntuitionBase; static char banner[80]; static struct NewWindow nw = { 0, 0, 640, 200, /* left, top, (max) width, (max) height */ 0, 1, /* detail pen, block pen */ 0, /* IDCMP flags */ SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | SIZEBBOTTOM | ACTIVATE | NOCAREREFRESH, /* window flags */ NULL, NULL, /* gadget, checkmark */ (UBYTE *)&banner[0], /* title of window */ NULL, NULL, /* screen, bitmap */ 200, 50, -1, -1, /* sizing limits */ WBENCHSCREEN, /* on the workbench */ }; APTR oldwindowptr; struct Process *mytask; struct MsgPort *keyboard, *consinp, *consoutp, *serinp, *seroutp, *timerp; struct IOExtSer serin, serout; struct IOStdReq consin, consout; struct timerequest tr; struct Window *win; char InputCharacter; int timeropen, serialopen; #ifdef AMIGADEVDRV int DeviceSignal; #endif struct timer worktimer; /* this is NOT a timer.device timer */ void worker(); #ifdef LATTICE extern struct { short error; char *msg; } os_errlist[]; extern int _OSERR, os_nerr; #endif static clean(why) char *why; { int i; #ifdef AMIGADEVDRV if (DeviceSignal >= 0) FreeSignal(DeviceSignal); #endif if (timeropen) CloseDevice(&tr); if (serialopen) CloseDevice(&serin); if (win) CloseWindow(win); if (consinp) DeletePort(consinp); if (consoutp) DeletePort(consoutp); if (serinp) DeletePort(serinp); if (seroutp) DeletePort(seroutp); if (timerp) DeletePort(timerp); mytask->pr_WindowPtr = oldwindowptr; if (why) { myoserr(why); } exit(0); } myoserr(why) char *why; { int i; fprintf(stderr, "%s: ", why); #ifdef LATTICE fprintf(stderr, "%d: ", _OSERR); for(i = 0; os_errlist[i].error < os_nerr; i++) if (os_errlist[i].error == _OSERR) fprintf(stderr, os_errlist[i].msg); #endif fprintf(stderr, "\r\n"); } /* Called at startup time to set up console I/O, memory heap */ ioinit() { extern char major_rev[], minor_rev[]; struct Screen *scr; mytask = (struct Process *) FindTask((char *) NULL); oldwindowptr = mytask->pr_WindowPtr; mytask->pr_WindowPtr = (APTR) -1; /* disable DOS requestors */ if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 33L)) == NULL) clean("No intuition: Version 1.2 of Amiga Systems Software required"); sprintf(banner, #ifdef AMIGADEVDRV "KA9Q Internet Protocol Package, v%s.%s (Amiga version %sD)", #else "KA9Q Internet Protocol Package, v%s.%s (Amiga version %s)", #endif major_rev, minor_rev, AMIGAVERSION); /* * Try to determine the size of the workbench screen */ scr = malloc(sizeof(struct Screen)); if (scr==NULL) clean("Can't alloc screen"); if (GetScreenData(scr, (ULONG) sizeof(struct Screen), WBENCHSCREEN, NULL) == TRUE) { nw.Width = scr->Width; nw.Height = scr->Height-20; nw.TopEdge = 19; } else fprintf(stderr, "Can't GetScreenData()\n"); free((char *)scr); if ((win = OpenWindow(&nw)) == NULL) clean("Can't open window"); if ((consinp = CreatePort("net:console in", 0L)) == NULL) clean("Can't create console port"); if ((consoutp = CreatePort("net:console out", 0L)) == NULL) clean("Can't create console port"); if ((timerp = CreatePort("net:timer", 0L)) == NULL) clean("Can't create timer port"); consin.io_Data = (APTR) win; consin.io_Length = sizeof(struct Window); if (OpenDevice("console.device", 0L, &consin, 0L) != 0L) clean("Can't open console device"); consout = consin; consin.io_Message.mn_ReplyPort = consinp; consin.io_Length = 1; consin.io_Data = (APTR) &InputCharacter; consin.io_Command = CMD_READ; SendIO(&consin); consout.io_Message.mn_ReplyPort = consoutp; consout.io_Command = CMD_WRITE; /* create and start up timer */ tr.tr_node.io_Message.mn_ReplyPort = timerp; if (OpenDevice("timer.device", UNIT_VBLANK, &tr, 0L) != 0L) clean("Can't open timer"); #ifdef AMIGADEVDRV if ((DeviceSignal = AllocSignal(-1)) == -1) clean("Can't allocate device signal"); #endif timeropen++; tr.tr_node.io_Command = TR_GETSYSTIME; DoIO(&tr); #ifdef DEBUG printf("System time is %ld\n", tr.tr_time.tv_secs); #endif setiss(tr.tr_time.tv_secs); tr.tr_node.io_Command = TR_ADDREQUEST; tr.tr_time.tv_secs = 0; tr.tr_time.tv_micro = MSPTICK*1000L; /* convert to microseconds */ SendIO(&tr); set_timer(&worktimer, 1500); /* set for 1.5 seconds */ worktimer.func = worker; #ifdef AMIGADEVDRV DriverInit(); /* install internet.device driver */ #endif start_timer(&worktimer); } /* Called just before exiting to restore console state */ iostop() { while(ifaces != NULLIF){ if(ifaces->stop != NULLFP) (*ifaces->stop)(ifaces); ifaces = ifaces->next; } #ifdef AMIGADEVDRV DriverShutdown(); #endif clean((char *)0); } #define BUFMAXCNT 150 static char conbuf[BUFMAXCNT]; static int concnt = 0; int amigaputchar(c) char c; { conbuf[concnt++] = c; if ((c == '\n') || (concnt == BUFMAXCNT)) amigaflush(); return c; } amigaflush() { if (concnt == 0) return; consout.io_Data = (APTR) conbuf; consout.io_Length = concnt; consout.io_Command = CMD_WRITE; DoIO(&consout); concnt = 0; } /* * Begin terrible, horrible hack. All output should be printed upon (into?) * the window we opened before. Here goes nothing... */ void printf(a, b, c, d, e, f, g, h, i, j, k) char *a; int b, c, d, e, f, g, h, i, j, k; { if (concnt) amigaflush(); sprintf(conbuf, a, b, c, d, e, f, g, h, i, j, k); consout.io_Data = (APTR) conbuf; consout.io_Length = strlen(conbuf); consout.io_Command = CMD_WRITE; DoIO(&consout); /* no use in doing this async */ } /* check active connections and update titles */ void check_connections() { extern struct tcb *tcbs[NTCB]; register struct tcb *tcb; register int i; int newlisten, newopn; static int listen = -1, opn = -1; static msg[80]; newlisten = newopn = 0; for(i=0; inext) if (tcb->state == LISTEN) newlisten++; else newopn++; if (newlisten != listen || newopn != opn) { listen = newlisten; opn = newopn; sprintf(msg, "Amiga Port by WA3YMH (TCP: listen: %d open: %d)", listen, opn); SetWindowTitles(win, -1L, msg); } } /* called every second or so */ void worker() { check_connections(); start_timer(&worktimer); } #if 0 /* processes any messages that Intuition sends us */ void Do_Intuition_Message(m) register struct IntuiMessage *m; { ULONG class; USHORT code, qualifier; class = m->Class; code = m->Code; qualifier = m->Qualifier; ReplyMsg((struct Message *) m); /* reply msg back to Intuition */ switch (class) { case INTUITICKS: check_connections(); break; } } #endif /* * wait for something to happen */ eihalt() { register struct IntuiMessage *msg; static ULONG mask = 0; if (mask == 0L) mask = 1L << consinp->mp_SigBit | 1L << serinp->mp_SigBit | 1L << timerp->mp_SigBit | #ifdef AMIGDEVDRV 1L << DeviceSignal | #endif #if 0 1L << win->UserPort->mp_SigBit | #endif 1L << seroutp->mp_SigBit; (void) Wait(mask); #if 0 while (msg = (struct IntuiMessage *)GetMsg(win->UserPort)) Do_Intuition_Message(msg); #endif } /* checks the time then ticks and updates ISS */ void check_time() { int32 iss(); if (CheckIO(&tr)) { WaitIO(&tr); (void) GetMsg(timerp); tick(); (void)iss(); tr.tr_time.tv_secs = 0; tr.tr_time.tv_micro = MSPTICK*1000L; /* convert to microseconds */ SendIO(&tr); } } /* Initialize asynch port "dev" */ /* * We will make the bold and rash assumption that the asy link will be used * for slip and slip-like stuff. That is, we assume that there is an * an end-of-frame character that we can have the serial.device driver look * for. Thus, we can fire up a single I/O request and have the whole frame * come back at once. */ int asy_init(dev, bufsize) int16 dev; unsigned bufsize; { char serinitstr[1]; int serinitlen; serinitstr[0] = FR_END; /* initialize initialization string to a */ serinitlen = 1; /* frame end to flush receiver */ if (serialopen) { printf("\namiga: Error - serial device already open.\n"); return 0; } if ((serinp = CreatePort("net:serin", 0L)) == NULL) clean("Can't create serial input port"); if ((seroutp = CreatePort("net:serout", 0L)) == NULL) clean("Can't create serial output port"); /* * Open serial device. */ serin.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE; /* ? */ serin.io_Status = 0; serin.io_RBufLen = bufsize; asy[dev].speed = serin.io_Baud = 2400; /* default speed */ if (OpenDevice("serial.device", 0L, &serin, 0L) != 0L) clean("Can't open serial device"); serialopen++; serin.IOSer.io_Message.mn_ReplyPort = serinp; serout = serin; serout.IOSer.io_Message.mn_ReplyPort = seroutp; asy[dev].buflen = bufsize; /* alloc input buffer */ if((asy[dev].input_buffer = malloc(asy[dev].buflen)) == NULL) clean("Can't allocate serial input buf"); serin.IOSer.io_Data = (APTR) asy[dev].input_buffer; serin.IOSer.io_Length = asy[dev].buflen; asy[dev].input_len = 0; /* clear input buffer */ serin.io_SerFlags = SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE; serin.IOSer.io_Flags = 0; SendIO(&serin); serout.IOSer.io_Data = (APTR) serinitstr; serout.IOSer.io_Length = serinitlen; serout.IOSer.io_Command = CMD_WRITE; serout.IOSer.io_Flags = 0; serout.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE; DoIO(&serout); } int asy_stop(iface) struct interface *iface; { if (iface->dev >= ASY_MAX) { fprintf(stderr, "asy_stop: bad dev %d\n", iface->dev); return; } AbortIO(&serin); AbortIO(&serout); CloseDevice(&serin); free(asy[iface->dev].input_buffer); /* release buffer */ serialopen--; } /* Set asynch line speed */ int asy_speed(dev,speed) int dev; int speed; { if (serialopen == 0) return; AbortIO(&serin); WaitIO(&serin); (void) GetMsg(serinp); asy[dev].speed = serin.io_Baud = speed; serin.io_ReadLen = 8; serin.io_WriteLen = 8; serin.io_StopBits = 1; serin.io_TermArray.TermArray0 = serin.io_TermArray.TermArray1 = (ULONG)FR_END << 24 | (ULONG)FR_END << 16 | FR_END << 8 | FR_END; serin.IOSer.io_Command = SDCMD_SETPARAMS; serin.IOSer.io_Flags = 0; DoIO(&serin); if (serin.IOSer.io_Error) printf("Bad I/O status %d on SETPARAMS\n", serin.IOSer.io_Error); serin.IOSer.io_Command = CMD_READ; serin.IOSer.io_Data = (APTR) asy[dev].input_buffer; serin.IOSer.io_Length = asy[dev].buflen; asy[dev].input_len = 0; /* clear input buffer */ serin.io_SerFlags = SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE; serin.IOSer.io_Flags = 0; /* no quick I/O */ SendIO(&serin); } /* Send a buffer to serial transmitter */ asy_output(dev,buf,cnt) unsigned dev; char *buf; unsigned short cnt; { /* * We 'know' that the transmitter is ready since we would not have * been called unless the previous I/O has been completed. */ WaitIO(&serout); GetMsg(seroutp); serout.IOSer.io_Data = (APTR) buf; serout.IOSer.io_Length = cnt; serout.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE; serout.IOSer.io_Flags = 0; /* no quick I/O */ serout.IOSer.io_Command = CMD_WRITE; SendIO(&serout); } /* Read characters from the keyboard, translating them to "real" ASCII * If none are ready, return the -1 from kbraw() */ kbread() { char c; if (CheckIO(&consin)) { WaitIO(&consin); (void) GetMsg(consinp); c = InputCharacter; consin.io_Length = 1; consin.io_Data = (APTR) &InputCharacter; consin.io_Command = CMD_READ; SendIO(&consin); /* start next read up */ return (c & 0xff); } return -1; /* nuthin here */ } /* Receive characters from asynch line * Returns count of characters read */ unsigned asy_recv(dev,buf,cnt) int dev; char *buf; unsigned cnt; { register int actual = 0; register long error; if (asy[dev].input_len == 0) { /* if buffer is empty.. */ if (CheckIO(&serin) == NULL) /* see if I/O has completed */ return 0; /* nope, not yet. */ if (error = WaitIO(&serin)) printf("(SERIN) WaitIO returns %d\n", error); if (serin.IOSer.io_Error) printf("Bad I/O stat %d (SERIN)\n", serin.IOSer.io_Error); (void) GetMsg(serinp); /* input has completed. fill in state variables */ asy[dev].input_len = serin.IOSer.io_Actual; asy[dev].input_p = asy[dev].input_buffer; #ifdef TRACE if (trace & 0x40000000) { int a, n, l = asy[dev].input_len; unsigned char *b = asy[dev].input_buffer; a = 0; printf("Raw serial input:\r\n"); while (l) { n = min(l, 16); fmtline(a, b, n); a += n; b += n; l -= n; } fflush(stdout); } #endif } if (asy[dev].input_len) { /* any chars in buffer left? */ actual = min(asy[dev].input_len, cnt); if (actual == 1) *buf = *asy[dev].input_p; /* usual case */ else movmem(asy[dev].input_p, buf, actual); asy[dev].input_len -= actual; asy[dev].input_p += actual; } if (asy[dev].input_len == 0) { /* if buffer is now empty */ serin.IOSer.io_Command = CMD_READ; serin.IOSer.io_Data = (APTR) asy[dev].input_buffer; serin.IOSer.io_Length = asy[dev].buflen; serin.io_SerFlags = SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE; serin.IOSer.io_Flags = 0; /* no quick I/O */ SendIO(&serin); } return actual; } int stxrdy(dev) { return (CheckIO(&serout) != NULL); } /* Create a directory listing in a temp file and return the resulting file * descriptor. If full == 1, give a full listing; else return just a list * of names. * * This function is very dependent on the workings of Aztec standard I/O; * it uses their mechanism for generating and deleting temporary files. */ FILE * dir(path,full) char *path; int full; { /*return (FILE *)NULL;*/ return(0L); } #if 0 bcmp(a,b,n) register char *a,*b; register int16 n; { while(n-- != 0){ if(*a++ != *b++) return 1; } return 0; } #endif