/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/go32/l1.c (maintained by: ???) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>Minor statt. */ static MAJOR majortab[MAX_MAJOR+1]; /* Tabelle der MAC-Treiber */ static int num_major = 0; /* Default-Handler. Diese koennen die MAC-Treiber-Handler ersetzen oder */ /* ergaenzen, indem der Aufruf durchgereicht wird. */ /* Geraet-Initialisierung. */ /* Das Geraet und alle Minors werden vorinitialisiert. Diese Funktion */ /* wird beim Systemstart nach erfolgreicher registrierung aufgerufen. */ static void default_l1init(void) { } /* Geraet-Deinitialisierung. */ /* Beim Runterfahren des Systems wird diese Routine aufgerufen. */ #define default_l1exit default_l1init /* Geraet-Behandlung */ /* Hier koennen staendige Aufgaben erledigt werden, z.B. die Interrupt- */ /* Buffer leeren und Frames an den L2 schicken. Nur hier darf auf L1- */ /* Strukturen zugegriffen werden, nie aus dem Interrupt. */ #define default_l1handle default_l1init /* Geraet-Konfiguration */ /* Hier werden Konfigurations/Test/Reset-Anfragen bearbeit. */ static void default_l1ctl(int req, int port) { PORTINFO *p = &portpar[port]; if (p->reset_port) portstat[port].reset_count++; p->reset_port = commandflag[port] = testflag[port] = FALSE; } /* Geraet-DCD */ /* Wenn moeglich sollte das Geraet hier seinen tatsaechlichen DCD-Status */ /* liefern. Es duerfen keine Interpretationen (z.B. Vollduplex) geschehen,*/ /* das macht der L2 selbst. */ static WORD default_l1dcd(PORTINFO *port) { return(0); } /* Feststellen, ob wir mit dem L1-MAC-Namen gemeint sind. Es wird */ /* immer minor 0 geliefert (nicht geeignet fuer KISS usw). */ static int default_l1istome(int major, char *devname) { if (strnicmp(majortab[major].name, devname, strlen(devname))==0) return(0); return(NO_MINOR); } /* Geraet-Timerbehandlung. */ static void default_l1timer(UWORD ticks) { } /* Geraet anschliessen */ /* Ein Geraet und Minor an einen Port anschliessen. Dies muss */ /* nicht immer Erfolg haben. Der Minor wurde mittels dem jeweiligen */ /* l1istome ermittelt. */ /* Ist checkonly TRUE, dann soll nur geprueft werden, ob ein Eintrag */ /* moeglich WAERE, aber NICHTS ausgefuehrt werden. */ static int default_l1attach(int port, int unused_minor, BOOLEAN unused_checkonly) { return(1); } /* Geraet-Abschalten */ /* Einen Port abschalten, wenn das Geraet eine Trennung zulaesst. */ static int default_l1detach(int unused_port) { return(1); } /* Geraet-Informationen */ /* what=HW_INF_IDENT sollte der Geraetename geliefert werden. Wenn das */ /* Geraet mehrere hat (z.B. KISS/SMACK/RKISS), soll es */ /* den aktuellen liefern (benutzt von SPARAM). */ /* what=HW_INF_INFO sollte max. 10 Zeichen Geraetekonfiguration liefern, */ /* im Normalfalle auch der Name, eventuell mit etwas */ /* mehr Info. */ /* what=... sollte spaeter mal hsbus_stat() u.ae. ersetzen */ static void default_l1info(int what, int port, MBHEAD *mbp) { switch (what) { case HW_INF_IDENT : case HW_INF_INFO : putstr(majortab[portpar[port].major].name, mbp); } } /* MAC-Treiber registrieren. Es werden die default-Handler eingetragen, */ /* nur die benoetigten Routinen muessen vom Treiber ersetzt werden. Jeder */ /* Treiber sollte vor der Registrierung pruefen, ob ueberhaupt ein Geraet */ /* im System vorhanden ist und sich ggfs garnicht installieren. Dies */ /* beschleunigt den allgemeinen Ablauf im L1. */ static MAJOR *register_major(void) { MAJOR *m; if (num_major > MAX_MAJOR) return(NULL); m = &majortab[++num_major]; m->istome = default_l1istome; m->init = default_l1init; m->exit = default_l1exit; m->handle = default_l1handle; m->ctl = default_l1ctl; m->dcd = default_l1dcd; m->attach = default_l1attach; m->detach = default_l1detach; m->info = default_l1info; m->timer = default_l1timer; return(m); } /* Einen Port mit einem MAC-Treiber verbinden. Falls der Port bereits */ /* belegt ist, wird vorher l1detach() aufgerufen. Dieser darf aber auch */ /* fehlschlagen (wenn der Port nicht umkonfigurierbar ist, z.B. Host- */ /* terminal). Der Geraetetreiber setzt nur seinen minor, den major */ /* setzt l1attach selbst (der Geraetetreiber kennt eigentlich seinen */ /* major nicht). */ int l1attach(int port, char *devname) { int major; int minor; PORTINFO *p = &portpar[port]; /* als erstes suchen wir einen passenden major */ for (major = 1; major <= num_major; major++) if ((minor = majortab[major].istome(major, devname)) != NO_MINOR) break; if (major > num_major) return(0); /* Geraet unbekannt */ if (!majortab[major].attach(port, minor, TRUE/*check only*/)) return(0); /* erstmal nur antesten */ /* hier angekommen ist das neue Geraet bereit, ein eventuell altes */ /* schalten wir aus. */ if (p->major != NO_MAJOR) l1detach(port); if (p->major == NO_MAJOR) { /* nur wenn Abschaltung erfolgreich war */ if (majortab[major].attach(port, minor, FALSE/*attach*/)) { p->major = major; return(1); } } return(0); /* Port belegt / nicht belegbar */ } /* Einen Port von einem MAC-Treiber trennen. Dies darf fehlschlagen, */ /* wenn z.B. der L1 anderweitig konfiguriert wurde (Linux). */ void l1detach(int port) { int major; MBHEAD *mbp; LHEAD *mlp; major = portpar[port].major; if (major != NO_MAJOR) if (majortab[major].detach(port)) portpar[port].major = NO_MAJOR; if (portpar[port].major == NO_MAJOR) { mlp = &txl2fl[port]; while ((LHEAD *)mlp->head != mlp) { mbp = (MBHEAD *)ulink((LEHEAD *)mlp->head); relink((LEHEAD *)mbp, (LEHEAD *)stfl.tail); } kick[port] = FALSE; } } /************************************************************************/ /* Initialisierung der Variablen und der Hardware */ /************************************************************************/ void l1init(void) { MAJOR *m; int i; PORTINFO *p; for (i=0, p = portpar; ireset_port = FALSE; /* Tnx an Odo */ p->speed = 12; p->major = NO_MAJOR; p->minor = -1; cd_timer[i] = 0; kick[i] = FALSE; /* kein TNC sendet */ testflag[i] = FALSE; commandflag[i] = FALSE; } blkbuf = malloc(BLOCKSIZE); if (blkbuf == NULL) memerr(); show_recovery = TRUE; register_majors(); for (m = &majortab[1]; m <= &majortab[num_major]; m++) m->init(); l1sclr("*"); } /************************************************************************/ /* Layer 1 deinitialisieren */ /*----------------------------------------------------------------------*/ void l1exit (void) { MAJOR *m; for (m = &majortab[1]; m <= &majortab[num_major]; m++) m->exit(); } /************************************************************************/ /* Timer-Behandlung fuer den L1 */ /* wird aus timsrv() herraus aufgerufen */ /*----------------------------------------------------------------------*/ void l1timr(UWORD ticks) { MAJOR *m; for (m = &majortab[1]; m <= &majortab[num_major]; m++) m->timer(ticks); } /************************************************************************/ /* Level1 RX/TX */ /* wird staendig in der main() Hauptschleife aufgerufen. */ /*----------------------------------------------------------------------*/ void l1rxtx(void) { MAJOR *m; int major; rounds_count++; /* Anzahl der Hauptschleifendurchlaeufe */ for (m = &majortab[major = 1]; major <= num_major; major++, m++) m->handle(); } /************************************************************************/ /* Markieren, dass fuer TNC #port Frames zum Senden vorliegen */ /*----------------------------------------------------------------------*/ void kicktx(int port) { kick[port] = TRUE; } /************************************************************************/ /* */ /* iscd(): Carrier Detect */ /* */ /* Ueberpruefung des Kanalstatus fuer einen Port. Wenn auf einem */ /* Kanal der Sender getastet ist, wird 2 geliefert. Wenn auf dem */ /* Kanal Daten empfangen werden, wird 1 geliefert. 0 wird geliefert, */ /* wenn der Kanal frei ist, oder auf Vollduplex geschaltet ist. */ /* */ /* Hinweis: Einige Geraete unterstuetzen diese Funktion nur ungenau */ /* (z.B. Tokenring) */ /* */ /*----------------------------------------------------------------------*/ WORD iscd(int port) { int state = 0; int major; PORTINFO *p; p = portpar+port; major = p->major; if (major != NO_MAJOR) { if ((LHEAD *)txl2fl[port].head != &txl2fl[port]) state |= TXBFLAG; return(state | majortab[major].dcd(p)); } return(state); } /************************************************************************/ /* Level1 Control */ /* eine Aktion fuer einen Hardware-Port nachfragen */ /*----------------------------------------------------------------------*/ void l1ctl(int req, int port) { int major; switch(req) { case L1CRES: portpar[port].reset_port = TRUE; break; case L1CCMD: commandflag[port] = TRUE; break; case L1CTST: testflag[port] = TRUE; } major = portpar[port].major; if (major != NO_MAJOR) majortab[major].ctl(req, port); } /* Infostring fuer den Port-Befehl zusammenbauen. */ void l1hwstr(int port, MBHEAD *mbp) { if (portpar[port].major == NO_MAJOR) putstr("OFF", mbp); else majortab[portpar[port].major].info(HW_INF_INFO, port, mbp); } /* Infostring fuer SAVEPARM zusammenbauen. */ void l1hwcfg(int port, MBHEAD *mbp) { if (portpar[port].major == NO_MAJOR) putstr("OFF", mbp); else majortab[portpar[port].major].info(HW_INF_IDENT, port, mbp); } /* * Blocktransferroutinen fuer den Level 1 * Message-Buffer koennen Blockweise in einen linearen Buffer umgewandelt * werden und wieder zurueck. Dies darf aber so ohne weiteres nur im * Level 1 erfolgen, da der Buffer zurueckgespult wird. */ static int cpymbflat(char *buf, MBHEAD *fbp) { MB *bp; LHEAD *llp = &fbp->mbl; /* Zeiger auf den Listenkopf */ int i = fbp->mbpc; /* Anzahl der Bytes im Frame */ for (bp = (MB *)llp->head; bp != (MB *)llp; bp = bp->nextmb, i -= sizeof_MBDATA, buf += sizeof_MBDATA) memcpy(buf, bp->data, sizeof_MBDATA); return(fbp->mbpc); } static MBHEAD *cpyflatmb(char *buf, int size) { MBHEAD *mbhd; MB *bp; LHEAD *llp; mbhd = (MBHEAD *)allocb(ALLOC_MBHEAD); /* einen Buffer fuer den Kopf */ mbhd->mbpc = size; /* soviel wird mal drinstehen */ llp = &mbhd->mbl; /* Zeiger auf den Listenkopf */ for ( ; size > 0; size -= sizeof_MBDATA, buf += sizeof_MBDATA) { memcpy((bp = (MB *)allocb(ALLOC_MB))->data, buf, sizeof_MBDATA); relink((LEHEAD *)bp, (LEHEAD *)llp->tail); } rwndmb(mbhd); /* mbbp richtig setzen */ return(mbhd); } #ifdef VANESSA #include "vanessa.c" #endif #ifdef EXTDEV #include "extdev.c" #endif #ifdef TOKENRING #include "tokenrng.c" #endif #ifdef COMKISS #include "kiss.c" #endif #ifdef SCC #include "scc.c" #endif #ifdef PAR96 #include "par.c" #endif #include "loop.c" #ifdef TCP_STACK #include "tcp.c" #endif /* TCP_STACK */ /* Geraetetabelle. */ /* In dieser Tabelle werden alle Geraete registriert. Bezuege aus L1.C */ /* auf Variablen der Treiber sind verboten. */ /* Die Reihenfolge hier bestimmt auch die Reihenfolge bei der STAT- */ /* Ausgabe. */ DEVTABLE devtable[] = { REGISTER_DEVICE("LOOPBACK", register_loopback), #ifdef TOKENRING REGISTER_DEVICE("TOKENRING", register_tokenring), #endif #ifdef COMKISS REGISTER_DEVICE("KISS", register_kiss), #endif #ifdef VANESSA REGISTER_DEVICE("VANESSA", register_vanessa), #endif #ifdef EXTDEV REGISTER_DEVICE("EXTDEV", register_extdev), #endif #ifdef SCC REGISTER_DEVICE("SCC", register_scc), #endif #ifdef PAR96 REGISTER_DEVICE("PAR96", register_par), #endif #ifdef TCP_STACK REGISTER_DEVICE("TCPIP", RegisterTCP), #endif /* TCP_STACK */ REGISTER_DEVICE(NULL, NULL) }; /* Hier werden alle majors nacheinander gebeten, sich zu registrieren. */ /* Sie muessen es aber nicht, falls z.B. keine Schnittstellen frei oder */ /* vorhanden sind. */ void register_majors(void) { DEVTABLE *t; for (t = devtable; t->reg_func; t++) t->major = t->reg_func(); } /* Aufzaehlen der vorhandenen Layer 1 Geraete. Dies sind nicht die */ /* tatsaechlich installierten, sondern die compilierten. */ void l1enum(MBHEAD *mbp) { DEVTABLE *t; for (t = devtable; t->reg_func; t++) { putstr(t->major ? " *" : " ", mbp); putstr(t->name, mbp); } } /* Information zu einem Geraet abrufen (Statistik). */ void l1stat(const char *devname, MBHEAD *mbp) { DEVTABLE *t; for (t = devtable; t->reg_func; t++) if (strcmp(t->name, devname) == 0 || *devname == '*') /* Name stimmt? */ if (t->major) majortab[t->major].info(HW_INF_STAT, 0, mbp); } /* Portstatistik loeschen */ void l1sclr(const char *devname) { DEVTABLE *t; for (t = devtable; t->reg_func; t++) if (strcmp(t->name, devname) == 0 || *devname == '*') /* Name stimmt? */ if (t->major) majortab[t->major].info(HW_INF_CLEAR, 0, NULL); } /* End of os/go32/l1.c */