📄 drsi.c
字号:
/*
* 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;
/* See if theres anything left to send - if there is, send it ! */
if((hp->sndbuf = dequeue(&hp->sndq)) == NULL){
/* Nothing left to send - return to receive */
write_scc(base, R5, Tx8|DTR); /* Tx off now */
write_scc(base, R0, ERR_RES); /* Reset error bits */
hp->tstate = IDLE;
hp->tx_state = drtx_idle;
hp->rstate = ENABLE;
hp->rx_state = drrx_enable;
drrx_enable(hp);
} else
drtx_tfirst(hp);
}
/* Write CTC register */
static void
write_ctc(base, reg, val)
uint16 base;
uint8 reg,val;
{
int i_state;
i_state = dirps();
/* Select register */
outportb(base+Z8536_MASTER,reg);
outportb(base+Z8536_MASTER,val);
restore(i_state);
}
/* Read CTC register */
static char
read_ctc(base, reg)
uint16 base;
uint8 reg;
{
uint8 c;
uint16 i;
int i_state;
i_state = dirps();
/* Select register */
outportb(base+Z8536_MASTER,reg);
/* Delay for a short time to allow 8536 to settle */
for(i=0;i<100;i++)
;
c = inportb(base+Z8536_MASTER);
restore(i_state);
return(c);
}
/* Initialize dr controller parameters */
static int
drchanparam(hp)
register struct drchan *hp;
{
uint16 tc;
long br;
register uint16 base;
int i_state;
/* Initialize 8530 channel for SDLC operation */
base = hp->base;
i_state = dirps();
switch(base & 2){
case 2:
write_scc(base,R9,CHRA); /* Reset channel A */
break;
case 0:
write_scc(base,R9,CHRB); /* Reset channel B */
break;
}
/* Deselect all Rx and Tx interrupts */
write_scc(base,R1,0);
/* Turn off external interrupts (like CTS/CD) */
write_scc(base,R15,0);
/* X1 clock, SDLC mode */
write_scc(base,R4,SDLC|X1CLK); /* SDLC mode and X1 clock */
/* Now some misc Tx/Rx parameters */
/* CRC PRESET 1, NRZI Mode */
write_scc(base,R10,CRCPS|NRZI);
/* Set up BRG and DPLL multiplexers */
/* Tx Clk from RTxC. Rcv Clk from DPLL, TRxC pin outputs BRG */
write_scc(base,R11,RCDPLL|TCRTxCP|TRxCOI|TRxCBR);
/* Null out SDLC start address */
write_scc(base,R6,0);
/* SDLC flag */
write_scc(base,R7,FLAG);
/* Set up the Transmitter but don't enable it */
/* DTR, 8 bit TX chars only - TX NOT ENABLED */
write_scc(base,R5,Tx8|DTR);
/* Receiver - initial setup only - more later */
write_scc(base,R3,Rx8); /* 8 bits/char */
/* Setting up BRG now - turn it off first */
write_scc(base,R14,BRSRC); /* BRG off, but keep Pclk source */
/* set the 32x time constant for the BRG */
br = hp->speed; /* get desired speed */
tc = ((XTAL/32)/br)-2; /* calc 32X BRG divisor */
write_scc(base,R12,tc); /* lower byte */
write_scc(base,R13,(tc>>8)); /* upper bite */
/* Time to set up clock control register for RECEIVE mode
* DRSI has xtal osc going to pclk at 4.9152 Mhz
* The BRG is sourced from that, and set to 32x clock
* The DPLL is sourced from the BRG. BRG is fed to the TRxC pin
* Transmit clock is provided by the BRG externally divided by
* 32 in the CTC counter 1 and 2.
* Receive clock is from the DPLL
*/
/* Following subroutine sets up and ENABLES the receiver */
drrx_enable(hp);
/* DPLL from BRG, BRG source is PCLK */
write_scc(hp->base,R14,BRSRC|SSBR);
/* SEARCH mode, keep BRG source */
write_scc(hp->base,R14,BRSRC|SEARCH);
/* Enable the BRG */
write_scc(hp->base,R14,BRSRC|BRENABL);
/* enable the receive interrupts */
write_scc(hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
write_scc(hp->base,R15,BRKIE); /* ABORT int */
write_scc(hp->base,R9,MIE|NV); /* master enable */
/* Now, turn on the receiver and hunt for a flag */
write_scc(hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
restore(i_state);
return 0;
}
/*
* Initialize the CTC (8536)
* Only the counter/timers are used - the IO ports are un-comitted.
* Channels 1 and 2 are linked to provide a /32 counter to convert
* the SIO BRG to a real clock for Transmit clocking.
* CTC 3 is left free running on a 10 mS period. It is always polled
* and therefore all interrupts from the chip are disabled.
*
* Updated 02/16/89 by N6TTO
* Changed to support the use of the second channel on the 8530.
* Added so that the driver works on the DRSI type 2 PC Adaptor
* which has 2 1200 bps modems.
*
*/
static void
drinitctc(port)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -