⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 drsi.c

📁 嵌入式TCP/IP协议栈。 C 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>
#include <dos.h>
#include <time.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "pktdrvr.h"
#include "netuser.h"
#include "drsi.h"
#include "ax25.h"
#include "trace.h"
#include "nospc.h"
#include "z8530.h"
#include "devparam.h"

static int32 dr_ctl(struct iface *iface,int cmd,int set,int32 val);
static int dr_raw(struct iface *iface,struct mbuf **bpp);
static int dr_stop(struct iface *iface);
static void dr_wake(struct drchan *hp,int rx_or_tx,
	void (*routine)(struct drchan *),int ticks);
static int drchanparam(struct drchan *hp);
static void drexint(struct drchan *hp);
static void drinitctc(unsigned port);
static void drrx_active(struct drchan *hp);
static void drrx_enable(struct drchan *hp);
static void drtx_active(struct drchan *hp);
static void drtx_defer(struct drchan *hp);
static void drtx_downtx(struct drchan *hp);
static void drtx_flagout(struct drchan *hp);
static void drtx_idle(struct drchan *hp);
static void drtx_rrts(struct drchan *hp);
static void drtx_tfirst(struct drchan *hp);
static char read_ctc(unsigned port,unsigned reg);
static void rx_fsm(struct drchan *hp);
static void tx_fsm(struct drchan *hp);
static void write_ctc(uint16 port,uint8 reg,uint8 val);

struct DRTAB Drsi[DRMAX];	/* Device table - one entry per card */
INTERRUPT (*Drhandle[])(void) = { dr0vec };  /* handler interrupt vector table */
struct drchan Drchan[2*DRMAX];	 /* channel table - 2 entries per card */
uint16 Drnbr;

/* Set specified routine to be 'woken' up after specified number
 * of ticks (allows CPU to be freed up and reminders posted);
 */
static void
dr_wake(hp, rx_or_tx, routine, ticks)
struct drchan *hp;
int rx_or_tx;
void (*routine)(struct drchan *);
int ticks;
{
	hp->w[rx_or_tx].wcall = routine;
	hp->w[rx_or_tx].wakecnt = ticks;
}

/* Master interrupt handler.  One interrupt at a time is handled.
 * here. Service routines are called from here.
 */
INTERRUPT (far *(drint)(dev))()
int dev;
{
	register char st;
	register uint16 pcbase, i;
	struct drchan *hpa,*hpb;
	struct DRTAB *dp;

	dp = &Drsi[dev];
	dp->ints++;
	pcbase = dp->addr;
	hpa = &Drchan[2 * dev];
	hpb = &Drchan[(2 * dev)+1];

yuk:
	/* Check CTC for timer interrupt */
	st = read_ctc(pcbase, Z8536_CSR3);
	if(st & Z_IP){
		/* Reset interrupt pending */
		write_ctc(pcbase, Z8536_CSR3, Z_CIP|Z_GCB);
		for(i=0;i<=1;i++){
			if(hpa->w[i].wakecnt){
				if(--hpa->w[i].wakecnt == 0){
					(hpa->w[i].wcall)(hpa);
				}
			}
			if(hpb->w[i].wakecnt){
				if(--hpb->w[i].wakecnt == 0){
					(hpb->w[i].wcall)(hpb);
				}
			}
		}
	}
	/* Check the SIO for interrupts */

	/* Read interrupt status register from channel A */
	while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0){
		/* Use IFs to process ALL interrupts pending
		 * because we need to check all interrupt conditions
		 */
		if(st & CHARxIP){
			/* Channel A Rcv Interrupt Pending */
			rx_fsm(hpa);
		}
		if(st & CHBRxIP){
			/* Channel B Rcv Interrupt Pending */
			rx_fsm(hpb);
		}
		if(st & CHATxIP){
			/* Channel A Transmit Int Pending */
			tx_fsm(hpa);
		}
		if(st & CHBTxIP){
			/* Channel B Transmit Int Pending */
			tx_fsm(hpb);
		}
		if(st & CHAEXT){
			/* Channel A External Status Int */
			drexint(hpa);
		}
		if(st & CHBEXT){
			/* Channel B External Status Int */
			drexint(hpb);
		}
		/* Reset highest interrupt under service */
		write_scc(hpa->base+CTL,R0,RES_H_IUS);

	} /* End of while loop on int processing */
	if(read_ctc(pcbase, Z8536_CSR3) & Z_IP)
		goto yuk;
	return dp->chain ? dp->oldvec : NULL;
}


/* DRSI SIO External/Status interrupts
 * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
 * Receiver automatically goes to Hunt on an abort.
 *
 * If the Tx Underrun interrupt hits, change state and
 * issue a reset command for it, and return.
 */
static void
drexint(hp)
register struct drchan *hp;
{
	register int base = hp->base;
	char st;
	int i_state;

	i_state = dirps();
	hp->exints++;

	st = read_scc(base+CTL,R0);     /* Fetch status */

	/* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
        /* Note that the TxEOM bit remains set once we go    */
	/* back to receive.  The following qualifications    */
	/* are necessary to prevent an aborted frame causing */
	/* a queued transmit frame to be tossed when in      */
	/* DEFER state on transmit.			     */
	if((hp->tstate != DEFER) && (hp->rstate==0) && (st & TxEOM)){
		if(hp->tstate != UNDERRUN){
			/* This is an unexpected underrun.  Discard the current
			 * frame (there's no way to rewind),  kill the transmitter
			 * and return to receive with a wakeup posted to get the
			 * next (if any) frame.  Any recovery will have to be done
			 * by higher level protocols (yuk).
			 */
			write_scc(base, R5, Tx8|DTR);	/* Tx off now */
			write_scc(base, R1, 0);		/* Prevent ext.status int */
			write_scc(base, R0, RES_Tx_P);  /* Reset Tx int pending */
			write_scc(base, R0, ERR_RES);
			write_scc(base, R0, RES_EOM_L); /* Reset underrun latch */
			free_p(&hp->sndbuf);
			hp->tstate = IDLE;
			hp->tx_state = drtx_idle;
			dr_wake(hp, TX, tx_fsm, hp->slotime);
			hp->rstate = ENABLE;
			hp->rx_state = drrx_enable;
			drrx_enable(hp);
		}
	}
	/* Receive Mode only
	 * This triggers when hunt mode is entered, & since an ABORT
	 * automatically enters hunt mode, we use that to clean up
	 * any waiting garbage
	 */
	if((hp->rstate != IDLE) && (st & BRK_ABRT)){
		if(hp->rcvbuf != NULL){
			hp->rcp = hp->rcvbuf->data;
			hp->rcvbuf->cnt = 0;
		}
		while(read_scc(base,R0) & Rx_CH_AV)
			(void) inportb(base+DATA);
		hp->aborts++;
		hp->rstate = ACTIVE;
		write_scc(base, R0, ERR_RES);
	}
	/* reset external status latch */
	write_scc(base,R0,RES_EXT_INT);
	restore(i_state);
}

/* Receive Finite State Machine - dispatcher */
static void
rx_fsm(hp)
struct drchan *hp;
{
	int i_state;

	i_state = dirps();
	hp->rxints++;
	(*hp->rx_state)(hp);
	restore(i_state);
}

/* drrx_enable
 * Receive ENABLE state processor
 */
static void
drrx_enable(hp)
struct drchan *hp;
{
	register uint16 base = hp->base;

	write_scc(base, R1, INT_ALL_Rx|EXT_INT_ENAB);
	write_scc(base, R15, BRKIE);	/* Allow ABORT Int */
	write_scc(base, R14, BRSRC|BRENABL|SEARCH);
	/* Turn on rx and enter hunt mode */
	write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);

	if(hp->rcvbuf != NULL){
		hp->rcvbuf->cnt = 0;
		hp->rcp = hp->rcvbuf->data;
	}
	hp->rstate = ACTIVE;
	hp->rx_state = drrx_active;
}

/* drrx_active
 * Receive ACTIVE state processor
 */
static void
drrx_active(hp)
struct drchan *hp;
{
	register uint16 base = hp->base;
	unsigned char rse,st;
	struct mbuf *bp;

	/* Allocate a receive buffer if not already present */
	if(hp->rcvbuf == NULL){
		bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
		if(bp == NULL){
			/* No buffer - abort the receiver */
			write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
			/* Clear character from rx buffer in SIO */
			(void) inportb(base+DATA);
			return;
		}
		hp->rcvbuf->cnt = 0; 
		hp->rcp = hp->rcvbuf->data;
	}

	st = read_scc(base, R0); /* get interrupt status from R0 */
	rse = read_scc(base,R1); /* get special status from R1 */

	if(st & Rx_CH_AV){
		/* there is a char to be stored
		 * read special condition bits before reading the data char
		 * (already read above)
		 */
		if(rse & Rx_OVR){
			/* Rx overrun - toss buffer */
			hp->rcp = hp->rcvbuf->data;	/* reset buffer pointers */
			hp->rcvbuf->cnt = 0;
			hp->rstate = RXERROR;	/* set error flag */
			hp->rovers++;		/* count overruns */
		} else if(hp->rcvbuf->cnt >= hp->bufsiz){
			/* Too large -- toss buffer */
			hp->toobig++;
			hp->rcp = hp->rcvbuf->data;	/* reset buffer pointers */
			hp->rcvbuf->cnt = 0;
			hp->rstate = TOOBIG;	/* when set, chars are not stored */
		}
		/* ok, we can store the received character now */
		if((hp->rstate == ACTIVE) && ((st & BRK_ABRT) == 0)){
			*hp->rcp++ = inportb(base+DATA); /* char to rcv buff */
			hp->rcvbuf->cnt++;		 /* bump count */
		} else {
			/* got to empty FIFO */
			(void) inportb(base+DATA);
			hp->rcp = hp->rcvbuf->data;	/* reset buffer pointers */
			hp->rcvbuf->cnt = 0;
			hp->rstate = RXABORT;
			write_scc(base,R0,ERR_RES);	/* reset err latch */
		}
	}
	/* The End of Frame bit is ALWAYS associated with a character,
	 * usually, it is the last CRC char.  Only when EOF is true can
	 * we look at the CRC byte to see if we have a valid frame
	 */
	if(rse & END_FR){
		hp->rxframes++;
		/* END OF FRAME -- Make sure Rx was active */
		if(hp->rcvbuf->cnt > 0){	/* any data to store */
			/* looks like a frame was received
			 * now is the only time we can check for CRC error
			 */
			if((rse & CRC_ERR) || (hp->rstate > ACTIVE) ||
			 (hp->rcvbuf->cnt < 10) || (st & BRK_ABRT)){
				/* error occurred; toss frame */
				if(rse & CRC_ERR)
					hp->crcerr++;	/* count CRC errs */
				hp->rcp = hp->rcvbuf->data;
				hp->rcvbuf->cnt = 0;
				hp->rstate = ACTIVE;   /* Clear error state */
			} else {
				/* Here we have a valid frame */
				hp->rcvbuf->cnt -= 2;    /* chuck FCS bytes */
				    /* queue it in */
				net_route(hp->iface,&hp->rcvbuf);
				hp->enqueued++;
				/* packet queued - reset buffer pointer */
				hp->rcvbuf = NULL;
			} /* end good frame queued */
		}  /* end check for active receive upon EOF */
	}
}

/*
 * TX finite state machine - dispatcher
 */
static void
tx_fsm(hp)
struct drchan *hp;
{
	int i_state;

	i_state = dirps();
	if(hp->tstate != DEFER && hp->tstate)
		hp->txints++;
	(*hp->tx_state)(hp);
	restore(i_state);
}

/* drtx_idle
 * Transmit IDLE transmit state processor
 */
static void
drtx_idle(hp)
struct drchan *hp;
{
	register uint16 base;

	/* Tx idle - is there a frame to transmit ? */
	if((hp->sndbuf = dequeue(&hp->sndq)) == NULL){
		/* Nothing to send - return to receive mode
		 * Turn Tx off - any trailing flag should have been sent
		 * by now
		 */
#ifdef DRSIDEBUG
		printf("Nothing to TX\n");
#endif
		base = hp->base;
		write_scc(base, R5, Tx8|DTR);   /* Tx off now */
		write_scc(base, R0, ERR_RES);	/* Reset error bits */

		/* Delay for squelch tail before enabling receiver */
		hp->rstate = ENABLE;
		hp->rx_state = drrx_enable;
		dr_wake(hp, RX, rx_fsm, hp->squeldelay);
	} else {
		/* Frame to transmit */
		hp->tstate = DEFER;
		hp->tx_state = drtx_defer;
		drtx_defer(hp);
	}
}

/* drtx_defer
 * Transmit DEFER state processor
 */
static void
drtx_defer(hp)
struct drchan *hp;
{
	register uint16 base = hp->base;

	/* We may have defered a previous tx attempt - in any event...
	 * Check DCD in case someone is already transmitting
	 * then check to see if we should defer due to P-PERSIST.
	 */

#ifdef DRSIDEBUG
	printf("drtx_defer - checking for DCD\n");
#endif
	if((read_scc(base+CTL, R0) & DCD) > 0){
		/* Carrier detected - defer */
		hp->txdefers++;
		dr_wake(hp, TX, tx_fsm, 10);	/* Defer for 100 mS */
#ifdef DRSIDEBUG
		printf("drtx_defer - TX deferred\n");
#endif
		return;
	}

#ifdef DRSIDEBUG
	printf("drtx_defer - checking for P-PERSIST backoff\n");
#endif
	/* P-PERSIST is checked against channel 3 of the 8536 which is
	 * the free running counter for the 10 mS tick; The counter
	 * goes through 0x6000 ticks per 10 mS or one tick every
	 * 407 nS - this is pretty random compared to the DOS time of
	 * day clock (0x40:0x6C) used by the other (EAGLE) drivers.
	 */
        if (hp->persist <= read_ctc(base,Z8536_CC3LSB)) {
#ifdef DRSIDEBUG
	    printf("drtx_defer - BACKOFF\n");
#endif
	    hp->txppersist++;
	    dr_wake (hp, TX, tx_fsm, hp->slotime);
	    return;
	}
	/* No backoff - set RTS and start to transmit frame */
	write_scc(base, R1, 0);		/* Prevent external status int */
	write_scc(base, R3, Rx8);	/* Turn Rx off */
	hp->rstate = IDLE;		/* Mark Rx as idle */
	hp->tstate = RRTS;
	hp->tx_state = drtx_rrts;
#ifdef DRSIDEBUG
	printf("drtx_defer - wake posted for drtx_rrts\n");
#endif
	write_scc(base, R9, 0);		/* Interrupts off */
	write_scc(base,R5,RTS|Tx8|DTR);	/* Turn tx on */
	dr_wake(hp, TX, tx_fsm, 10);
}

/* drtx_rrts
 * Transmit RRTS state processor
 */
static void
drtx_rrts(hp)
struct drchan *hp;
{
	register uint16 base = hp->base;

	write_scc(base, R9, 0);	/* Interrupts off */
	write_scc(base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);	/* Tx now on */
	hp->tstate = TFIRST;
	hp->tx_state = drtx_tfirst;
#ifdef DRSIDEBUG
	printf("8530 Int status %x\n", read_scc(base+CHANA,R3)); 
	printf("drtx_rrts - Wake posted for TXDELAY\n");
#endif
	dr_wake(hp, TX, tx_fsm, hp->txdelay);
}
    
/* drtx_tfirst
 * Transmit TFIRST state processor
 */
static void
drtx_tfirst(hp)
struct drchan *hp;
{
	register uint16 base = hp->base;
	char c;
	
	/* Copy data to a local buffer to save on mbuf overheads
	 * during transmit interrupt time.
	 */
	hp->drtx_cnt = len_p(hp->sndbuf);
	hp->drtx_tcp = hp->drtx_buffer;
	
	pullup(&hp->sndbuf, hp->drtx_tcp, hp->drtx_cnt);
	
	/* Transmit the first character in the buffer */
	c = *hp->drtx_tcp++;
	hp->drtx_cnt--;

	write_scc(base, R0, RES_Tx_CRC);	/* Reset CRC */
	write_scc(base, R0, RES_EOM_L);		/* Reset underrun latch */
	outportb(base+DATA, c);			/* Output first character */
	write_scc(base, R15, TxUIE);		/* Allow underrun ints only */
	write_scc(base, R1, TxINT_ENAB|EXT_INT_ENAB); /* Tx/Ext status ints on */
	write_scc(base, R9, MIE|NV);		/* master enable */
	hp->tstate = ACTIVE;
	hp->tx_state = drtx_active;
}

/* drtx_active
 * Transmit ACTIVE state processor
 */
static void
drtx_active(hp)
struct drchan *hp;
{
	if(hp->drtx_cnt-- > 0){
		/* Send next character */
		outportb(hp->base+DATA, *hp->drtx_tcp++);
	} else {
		/* No more to send - wait for underrun to hit */
		hp->tstate = UNDERRUN;
		hp->tx_state = drtx_flagout;
		free_p(&hp->sndbuf);
		write_scc(hp->base, R0, RES_EOM_L);  /* Send CRC on underrun */
		write_scc(hp->base, R0, RES_Tx_P);   /* Reset Tx Int pending */
	}
}

/* drtx_flagout
 * Transmit FLAGOUT state processor
 */
static void
drtx_flagout(hp)
struct drchan *hp;
{
	/* Arrive here after CRC sent and Tx interrupt fires.
	 * Post a wake for ENDDELAY
	 */

	hp->tstate = UNDERRUN;
	hp->tx_state = drtx_downtx;
	write_scc(hp->base, R9, 0);
	write_scc(hp->base, R0,  RES_Tx_P);
	dr_wake(hp, TX, tx_fsm, hp->enddelay);
}

/* drtx_downtx
 * Transmit DOWNTX state processor
 */
static void
drtx_downtx(hp)
struct drchan *hp;
{
	register int base = hp->base;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -