/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File os/go32/par.c (maintained by: ???) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD>> 8) #if 0 #ifndef outp #define outp(p,b) outportb(p,b) #endif #ifndef inp #define inp(p) inportb(p) #endif #endif #define not0(par) (par ? par : 1) #define TX_IDLE 0 #define TX_DWAIT 1 #define TX_DELAY 2 #define TX_ACTIVE 3 #define TX_FLUSH 4 #define TX_TAIL 5 /* PAR */ #define TXD 0x01 #define PTT 0x02 #define BURST 0x04 #define DCDBIT 0x10 #define RXD 0x20 #define IRQEN 0x10 #define DCDCOUNT 5 #define DCDABORT 5 #define DCDLIMIT 15 /* L1 */ #define MIN_LEN 15 #define STUFF 5 #define FLAG 6 #define ABRT 7 #define FREE 30 /* CRC */ #define CRC_RESET 0xFFFF #define CRC_MASK 0x8408 #define CRC_CHECK 0xF0B8 typedef struct __par_struct { int l2port; int parbase; int parirq; int paroldmask; int port; int irq; int bit_cnt; int idle; int shift; int lastbit; int frm_len; unsigned short crc; unsigned short fcs; int dcd_cnt; int dcd; int sync; int tx_state; char *tx_buf; char *tx_ptr; int tx_len; int tx_bitcnt; int tx_idle; int tx_bit; int tx_timer; unsigned short tx_fcs; unsigned tx_shift; unsigned long scr; int slottime; int persistance; int tailtime; int txdelay; int flags; unsigned burstbuf; unsigned overruns; unsigned underruns; unsigned crcerrors; unsigned lenerrors; MBHEAD *rxfhd; } __par_struct; static __par_struct par96tab[PARCHANS]; static int par_major = 0; static UWORD *parbuf, *parin, *parout; static void par_int(int); /* Wenn der Sender keine Daten mehr ausstehen hat, wird ein weiteres * Frame in den Sendebuffer kopiert. */ static void par_put_frame(__par_struct *par) { MBHEAD *fbp; int port; LHEAD *l2flp; if (par->tx_len == 0) { /* erst senden wenn alles raus ist */ if ((port = par->l2port) == -1) return; if (kick[port]) { /* ein weiteres Frame aus der Sendeliste holen */ l2flp = &txl2fl[port]; ulink((LEHEAD *)(fbp = (MBHEAD *) l2flp->head)); kick[port] = ((LHEAD *)l2flp->head != l2flp); par->tx_len = cpymbflat(par->tx_ptr = par->tx_buf, fbp); relink((LEHEAD *)fbp, /* als gesendet betrachten und in */ (LEHEAD *)stfl.tail); /* die gesendet Liste umhaengen */ disable(); if (par->tx_state == TX_IDLE) { par->tx_timer = not0 (par->slottime); par->tx_state = TX_DWAIT; } enable(); } } } /* Der PAR-Empfangs-Ringbuffer wird geleert. Dort werden von allen Kanaelen * Empfangsdaten gesammelt. Das Format entspricht dem alten l1put(). */ static void par_get_frame(void) { int minor; MBHEAD **rxfbpp; unsigned action; __par_struct *par = par96tab; #ifndef __GO32__ UWORD *_parin; disable(); _parin = parin; enable(); #else #define _parin parin #endif while (parout != _parin) { action = *parout++; /* Zeichen aus dem Ringbuffer lesen */ if (parout >= parbuf+PAR_RXSIZE) parout = parbuf; minor = (action>>8) & 0x7F; par = par96tab + minor; rxfbpp = &par->rxfhd; /* Adresse RX-Framezeiger */ if (!(action & 0x8000)) /* Zeichen oder Befehl ? */ { /* Zeichen : */ if (!*rxfbpp) /* RX-Frame aktiv ? */ { *rxfbpp = (MBHEAD *)allocb(); /* nein - neues anlegen */ (*rxfbpp)->l2port = par->l2port; /* fuer port */ } putchr(action & 0xFF,*rxfbpp); /* Zeichen in Frame */ } else /* Befehl : */ if (*rxfbpp) /* nur wenn Frame aktiv */ { /* Befehl ausfuehren */ if (action & 0x0001) /* Frame in Muelleimer */ relink((LEHEAD *)*rxfbpp, (LEHEAD *)trfl.tail); else { /* Frame in RX-Liste */ if ((*rxfbpp)->mbpc > 2) /* FCS eleminieren */ (*rxfbpp)->mbpc -= 2; /* das erste Byte kommt */ /* noch vor HUNT */ relink((LEHEAD *)*rxfbpp, (LEHEAD *)rxfl.tail); } *rxfbpp = NULL; /* kein RX-Frame aktiv */ } } } static void par(void) { __par_struct *par; par_get_frame(); for (par = par96tab; par < par96tab+PARCHANS; par++) if (par->parbase) par_put_frame(par); } static WORD par_dcd(PORTINFO *port) { __par_struct *par; int state = 0; par = &par96tab[port->minor]; if (par->tx_state) state |= PTTFLAG; if (par->dcd) state |= DCDFLAG; return(state); } static void par_ctl(int req, int port) { __par_struct *par; int minor; PORTINFO *p; p = portpar+port; minor = p->minor; par = &par96tab[minor]; switch (req) { case L1CCMD : case L1CRES : if (p->speed != 192) p->speed = 96; par->slottime = p->slottime; par->persistance = p->persistance; par->txdelay = p->txdelay; par->tailtime = TAILTIME; par->flags = p->l1mode; par->tx_state = par->tx_timer = 0; par->tx_len = 0; par->dcd = 0; outp (par->parbase, PTT | BURST); outp (par->parbase + 2, inp (par->parbase + 2) | IRQEN); break; } default_l1ctl(minor, req); /* Flags loeschen */ }; static int par_attach(int port, int minor, BOOLEAN check_only) { __par_struct *par; par = &par96tab[minor]; if (par_major) { if (par->l2port == -1) { if (!check_only) { par->l2port = port; portpar[port].minor = minor; par_ctl(L1CRES, port); } return(1); } if (par->l2port == port) return(1); } return(0); /* versuchte Doppeleintragung */ } static int par_detach(int port) { __par_struct *par = &par96tab[portpar[port].minor]; par->l2port = -1; outp (par->parbase + 2, inp (par->parbase + 2) & ~IRQEN); outp (par->parbase, PTT | BURST); return(1); } static void par_info(int what, int port, MBHEAD *mbp) { int minor, cnt; __par_struct *par; minor = portpar[port].minor; switch (what) { case HW_INF_IDENT : case HW_INF_INFO : putprintf(mbp, "PAR%u", minor); break; case HW_INF_STAT : for (minor = cnt = 0, par = par96tab; minor < PARCHANS; minor++, par++) if (par->l2port != -1) { if (cnt++ == 0) putstr("\rPAR-Statistics:\r\r", mbp); putprintf(mbp, " PAR%u RxOvr: %5u TxUnd: %5u RxCRC: %5u RxLen: %5u\r", minor, par->overruns, par->underruns, par->crcerrors, par->lenerrors); } break; case HW_INF_CLEAR : par = &par96tab[minor]; par->overruns = par->underruns = par->crcerrors = par->lenerrors = 0; /* durchfallen */ default : default_l1info(what, port, mbp); } } /* SCC-Modes: t -> Sendetakt extern (DF9IC) e -> Sendetakt BRG (32-fach) -> Sendetakt DPLL (32-fach) r -> Empfangstakt extern (DF9IC) -> Empfangstakt DPLL */ static void parput(UWORD action) { *parin++ = action; if (parin >= parbuf+PAR_RXSIZE) parin = parbuf; } #define rxput(port, val) parput (((port) << 8) | (val)) #define rxeof(port) parput (((port) << 8) | 0x8000) #define rxdiscard(port) parput (((port) << 8) | 0x8001) /*** HDLC ******************************************************************/ void hdlc_put_word(int minor, struct __par_struct *par, unsigned burstbuf) { int bit; int dcd; int cnt; dcd = par->flags & MODE_c; for (cnt = 16; cnt--; ) { bit = burstbuf & 1; burstbuf >>= 1; par->scr = (par->scr << 1) | (bit != par->lastbit); par->lastbit = bit; bit = !((UWORD) par->scr & 1) ^ !((UWORD) par->scr & 0x1000) ^ !( par->scr & 0x20000L); if (!bit) { if (par->idle < STUFF) { par->idle = 0; goto shift_bit; } if (par->idle == FLAG) { if ( dcd && par->dcd_cnt < DCDLIMIT && ++par->dcd_cnt == DCDCOUNT) { par->dcd = TRUE; } if (par->frm_len) { if ( par->sync && par->frm_len >= MIN_LEN+2 && par->bit_cnt == 1 && par->fcs == CRC_CHECK) { rxeof(minor); } else rxdiscard(minor); par->frm_len = 0; } par->bit_cnt = 8; par->sync = TRUE; par->crc = CRC_RESET; } par->idle = 0; } else { if (par->idle < FREE) { if (++par->idle < ABRT) { shift_bit: if (par->sync) { if (par->shift >>= 1, bit) par->shift |= 0x80; par->crc = (par->crc >> 1) ^ ((bit ^ par->crc) & 1 ? CRC_MASK : 0); if (--par->bit_cnt == 0) { /* par->sync = ! */ rxput (minor, par->shift); par->fcs = par->crc; par->bit_cnt = 8; par->frm_len++; } } } else { if (dcd) { if (par->dcd_cnt > DCDABORT) par->dcd_cnt -= DCDABORT; else par->dcd_cnt = 0; if (par->dcd_cnt < DCDCOUNT) { par->dcd = FALSE; } } par->sync = FALSE; } } } } } unsigned hdlc_get_word(int minor, __par_struct *par) { int bit; int cnt; int shift; for (cnt = 16; cnt--; ) { /* wenn wir Daten senden, muessen wir das Stuffing beruecksichtigen */ if ( par->tx_idle == STUFF && ( par->tx_state == TX_ACTIVE || par->tx_state == TX_FLUSH)) { par->tx_bit ^= 1; par->tx_idle = 0; } else { if (!par->tx_bitcnt) { switch (par->tx_state) { case TX_DELAY: if (par->tx_timer) { par->tx_shift = SDLC_FLAG; par->tx_bitcnt = 8; break; } par->tx_fcs = CRC_RESET; par->tx_idle = 0; par->tx_state = TX_ACTIVE; case TX_ACTIVE: if (par->tx_ptr >= par->tx_buf + par->tx_len) { par->tx_state = TX_FLUSH; par->tx_shift = ~par->tx_fcs; par->tx_bitcnt = 16; par->tx_len = 0; } else { par->tx_shift = *par->tx_ptr++; par->tx_bitcnt = 8; } break; case TX_FLUSH: par->tx_timer = TAILTIME; par->tx_state = TX_TAIL; case TX_TAIL: par->tx_shift = SDLC_FLAG; par->tx_bitcnt = 8; break; } } if (par->tx_shift & 1) par->tx_idle++; else { par->tx_bit ^= 1; par->tx_idle = 0; } par->tx_fcs = (par->tx_fcs >> 1) ^ ((par->tx_shift ^ par->tx_fcs) & 1 ? CRC_MASK : 0); par->tx_shift >>= 1; par->tx_bitcnt--; } par->scr = (par->scr << 1) | (bit = par->tx_bit ^ !((UWORD) par->scr & 0x800) ^ !( par->scr & 0x10000L)); shift >>= 1; if (bit) shift |= 0x8000; } return(shift); } /*** PAR RX *****************************************************************/ void par_rx(int minor) { unsigned burstbuf; int port_inp; int port_out; int cnt; __par_struct *par = par96tab+minor; port_out = par->parbase; port_inp = par->parbase+1; /* Die Daten als Burst lesen, damit wieder Platz in der FIFO ist */ for (cnt = 16; cnt--; ) { burstbuf >>= 1; if (inp(port_inp) & RXD) burstbuf |= 0x8000; outp (port_out, PTT); outp (port_out, PTT | BURST); } /* DCD fuer PicPar/PicPar97 */ if (!(par->flags & MODE_c)) par->dcd = inp (port_inp) & DCDBIT; #if 0 hdlc_put_word(minor, par, burstbuf); #endif } /*** PAR TX *****************************************************************/ void par_tx(int minor) { int bit; int cnt; int port_out; unsigned shift; __par_struct *par = par96tab+minor; port_out = par->parbase; /* zuerst werden die vorbereiteten Daten gesendet */ shift = par->burstbuf; for (cnt = 16; cnt--; ) { bit = shift & 1; shift >>= 1; outp(port_out, bit); outp(port_out, bit | BURST); } #if 0 par->burstbuf = hdlc_get_word(minor, par); #endif } static void par_timer (UWORD ticks) { __par_struct *par; int minor; if (par_major == 0) return; for (minor = 0, par = par96tab; minor < PARCHANS; minor++, par++) if (par->l2port != -1) { #if 1 hdlc_put_word(minor, par, hdlc_get_word(minor, par)); #endif disable (); if (par->tx_timer) if (par->tx_timer <= ticks) { par->tx_timer = 0; switch (par->tx_state) { case TX_DWAIT: if ( (par->flags & MODE_d) || ( (!par->dcd) && ((rand()&0xff) <= par->persistance) ) ) { par->tx_timer = not0(par->txdelay); par->tx_state = TX_DELAY; } else par->tx_timer = not0(par->slottime); break; case TX_TAIL: outp(par->parbase, PTT | BURST); par->tx_state = TX_IDLE; } } else par->tx_timer -= ticks; enable (); } } /*** PAR Interrupt **********************************************************/ void par_int(int minor) { if (par96tab[minor].tx_state > TX_DWAIT) par_tx(minor); else par_rx(minor); } /* Defaultparameter setzen */ static int par_init(void) { char tmp[10]; char *str; __par_struct *par; int minor; unsigned parbase; unsigned parirq; int used; used = 0; for (par = par96tab, minor = 0; minor < PARCHANS; minor++, par++) { par->parbase = 0; par->l2port = -1; sprintf(tmp, "PAR%u", minor); if ((str = getenv(tmp)) != NULL) { parbase = parirq = 0; sscanf(str, "%x,%u", &parbase, &parirq); if (parbase && parirq) { if ((parbuf = malloc(PAR_RXSIZE*sizeof(UWORD))) == NULL) return(0); parin = parout = parbuf; if ((par->tx_buf = malloc(PAR_TXSIZE)) == NULL) return(0); par->tx_len = 0; par->rxfhd = NULL; par->parirq = parirq; par->parbase = parbase; disable(); /* Interrupt aus */ allocirq(parirq, 0, par_int, 0); /* neuen Vektor setzen */ par->paroldmask = getmask(parirq); maskon(parirq); enable(); printf("--- /dev/PAR%u (0x%03X,IRQ%u) detected.\n", minor, parbase, parirq); used++; } } } return(used); /* eine Karte gefunden/konfiguriert ? */ } static void par_exit(void) { __par_struct *par; int minor; if (par_major) { for (minor = 0, par = par96tab; minor < PARCHANS; minor++, par++) if (par->parbase) { if (par->l2port) par_detach(par->l2port); if (par->paroldmask) maskoff(par->parirq); freeirq(par->parirq); } } } static int register_par(void) { MAJOR *m; if (par_init()) { m = register_major(); m->name = "PAR96"; m->exit = par_exit; m->handle = par; m->ctl = par_ctl; m->dcd = par_dcd; m->attach = par_attach; m->detach = par_detach; m->info = par_info; m->timer = par_timer; return(par_major = num_major); } return(0); } #undef rxput #undef rxeof #undef rxdiscard /* End of os/go32/par.c */