📄 drsi.c
字号:
/* 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)
unsigned port;
{
long i;
/* Initialize 8536 CTC */
/* Initialize 8536 */
/* Start by forcing chip into known state */
(void) read_ctc(port, Z8536_MICR);
write_ctc(port, Z8536_MICR, 0x01); /* Reset the CTC */
for(i=0;i < 1000L; i++) /* Loop to delay */
;
write_ctc(port, Z8536_MICR, 0x00); /* Clear reset and start init seq. */
/* Wait for chip to come ready */
while((read_ctc(port, Z8536_MICR)) != 0x02)
;
write_ctc(port, Z8536_MICR, 0xa6); /* MIE|NV|CT_VIS|RJA */
write_ctc(port, Z8536_MCCR, 0xf4); /* PBE|CT1E|CT2E|CT3E|PAE */
write_ctc(port, Z8536_CTMS1, 0xe2); /* Continuous,EOE,ECE, Pulse output */
write_ctc(port, Z8536_CTMS2, 0xe2); /* Continuous,EOE,ECE, Pulse output */
write_ctc(port, Z8536_CTMS3, 0x80); /* Continuous,Pulse output */
write_ctc(port, Z8536_CT1MSB, 0x00); /* Load time constant CTC #1 */
write_ctc(port, Z8536_CT1LSB, 0x10);
write_ctc(port, Z8536_CT2MSB, 0x00); /* Load time constant CTC #2 */
write_ctc(port, Z8536_CT2LSB, 0x10);
write_ctc(port, Z8536_CT3MSB, 0x60); /* Load time constant CTC #3 */
write_ctc(port, Z8536_CT3LSB, 0x00);
write_ctc(port, Z8536_IVR, 0x06);
/* Set port direction bits in port A and B
* Data is input on bits d1 and d5, output on d0 and d4.
* The direction is set by 1 for input and 0 for output
*/
write_ctc(port, Z8536_PDCA, 0x22);
write_ctc(port, Z8536_PDCB, 0x22);
write_ctc(port, Z8536_CSR1, Z_GCB|Z_TCB); /* Start CTC #1 running */
write_ctc(port, Z8536_CSR2, Z_GCB|Z_TCB); /* Start CTC #2 running */
write_ctc(port, Z8536_CSR3, Z_IE|Z_GCB|Z_TCB); /* Start CTC #3 running */
}
/* Attach a DRSI interface to the system
* argv[0]: hardware type, must be "drsi"
* argv[1]: I/O address, e.g., "0x300"
* argv[2]: vector, e.g., "2"
* argv[3]: mode, must be "ax25"
* argv[4]: iface label, e.g., "dr0"
* argv[5]: receiver packet buffer size in bytes
* argv[6]: maximum transmission unit, bytes
* argv[7]: iface speed for channel A
* argv[8]: iface speed for channel B (defaults to same as A if absent)
* argv[9]: First IP address, optional (defaults to Ip_addr)
* argv[10]: Second IP address, optional (defaults to Ip_addr)
*/
int
dr_attach(argc,argv)
int argc;
char *argv[];
{
register struct iface *if_pca,*if_pcb;
struct drchan *hp;
int dev;
char *cp;
/* Quick check to make sure args are good and mycall is set */
if(setencap(NULL,argv[3]) == -1){
printf("Mode %s unknown for interface %s\n",
argv[3],argv[4]);
return -1;
}
if(if_lookup(argv[4]) != NULL){
printf("Interface %s already exists\n", argv[4]);
return -1;
}
if(Mycall[0] == '\0'){
printf("set mycall first\n");
return -1;
}
/* Note: More than one card can be supported if you give up a COM:
* port, thus freeing up an IRQ line and port address
*/
if(Drnbr >= DRMAX){
printf("Only %d DRSI controller(s) supported right now!\n",DRMAX);
return -1;
}
dev = Drnbr++;
/* Initialize hardware-level control structure */
Drsi[dev].addr = htoi(argv[1]);
Drsi[dev].vec = atoi(argv[2]);
if(strchr(argv[2],'c') != NULL)
Drsi[dev].chain = 1;
else
Drsi[dev].chain = 0;
/* Save original interrupt vector */
Drsi[dev].oldvec = getirq(Drsi[dev].vec);
/* Set new interrupt vector */
if(setirq(Drsi[dev].vec,Drhandle[dev]) == -1){
printf("IRQ %u out of range\n",Drsi[dev].vec);
Drnbr--;
}
/* Initialize the CTC */
drinitctc(Drsi[dev].addr);
/* Create iface structures and fill in details */
if_pca = (struct iface *)callocw(1,sizeof(struct iface));
if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
if_pca->addr = if_pcb->addr = Ip_addr;
if(argc > 9)
if_pca->addr = resolve(argv[9]);
if(argc > 10)
if_pcb->addr = resolve(argv[10]);
if(if_pca->addr == 0 || if_pcb->addr == 0){
printf(Noipaddr);
free(if_pca);
free(if_pcb);
return -1;
}
/* Append "a" to iface associated with A channel */
if_pca->name = mallocw((unsigned)strlen(argv[4])+2);
strcpy(if_pca->name,argv[4]);
strcat(if_pca->name,"a");
/* Append "b" to iface associated with B channel */
if_pcb->name = mallocw((unsigned)strlen(argv[4])+2);
strcpy(if_pcb->name,argv[4]);
strcat(if_pcb->name,"b");
if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
if_pcb->ioctl = if_pca->ioctl = dr_ctl;
if_pca->dev = 2*dev; /* dr0a */
if_pcb->dev = 2*dev + 1; /* dr0b */
if_pcb->stop = if_pca->stop = dr_stop;
if_pcb->raw = if_pca->raw = dr_raw;
setencap(if_pca,argv[3]);
setencap(if_pcb,argv[3]);
if(if_pcb->hwaddr == NULL)
if_pcb->hwaddr = mallocw(sizeof(Mycall));
memcpy(if_pcb->hwaddr,&Mycall,sizeof(Mycall));
if(if_pca->hwaddr == NULL)
if_pca->hwaddr = mallocw(sizeof(Mycall));
memcpy(if_pca->hwaddr,&Mycall,sizeof(Mycall));
/* Link em in to the iface chain */
if_pca->next = if_pcb;
if_pcb->next = Ifaces;
Ifaces = if_pca;
/* set params in drchan table for CHANNEL B */
hp = &Drchan[2*dev+1]; /* dr1 is offset 1 */
hp->iface = if_pcb;
hp->stata = Drsi[dev].addr + CHANA + CTL; /* permanent status */
hp->statb = Drsi[dev].addr + CHANB + CTL; /* addrs for CHANA/B*/
if(argc > 8){
/* Separate speed for channel B */
hp->speed = (uint16)atoi(argv[8]);
} else {
/* Set speed to same as for channel A */
hp->speed = (uint16)atoi(argv[7]);
}
hp->base = Drsi[dev].addr + CHANB;
hp->bufsiz = atoi(argv[5]);
hp->drtx_buffer = mallocw(if_pcb->mtu+100);
hp->tstate = IDLE;
hp->tx_state = drtx_idle;
hp->w[RX].wcall = NULL;
hp->w[RX].wakecnt = 0;
hp->w[TX].wcall = NULL;
hp->w[TX].wakecnt = 0;
/* default KISS Params */
hp->txdelay = 25; /* 250 Ms */
hp->persist = 64; /* 25% persistence */
hp->slotime = 10; /* 100 Ms */
hp->squeldelay = 20; /* 200 Ms */
hp->enddelay = 10; /* 100 Ms */
write_scc(hp->stata,R9,FHWRES); /* Hardware reset */
/* Disable interrupts with Master interrupt ctrl reg */
write_scc(hp->stata,R9,0);
drchanparam(hp);
/* Initialize buffer pointers */
hp->rcvbuf = NULL;
hp->rcvbuf->cnt = 0;
hp->sndq = NULL;
/* set params in drchan table for CHANNEL A */
hp = &Drchan[2*dev]; /* dr0a is offset 0 */
hp->iface = if_pca;
hp->speed = (uint16)atoi(argv[7]);
hp->base = Drsi[dev].addr + CHANA;
hp->bufsiz = atoi(argv[5]);
hp->drtx_buffer = mallocw(if_pca->mtu+100);
hp->tstate = IDLE;
hp->tx_state = drtx_idle;
hp->w[RX].wcall = NULL;
hp->w[RX].wakecnt = 0;
hp->w[TX].wcall = NULL;
hp->w[TX].wakecnt = 0;
/* default KISS Params */
hp->txdelay = 30; /* 300 Ms */
hp->persist = 64; /* 25% persistence */
hp->slotime = 10; /* 100 Ms */
hp->squeldelay = 20; /* 200 Ms */
hp->enddelay = 10; /* 100 Ms */
drchanparam(hp);
/* Initialize buffer pointers */
hp->rcvbuf = NULL;
hp->rcvbuf->cnt = 0;
hp->sndq = NULL;
write_scc(hp->base,R9,MIE|NV); /* master interrupt enable */
/* Enable interrupt in 8259 interrupt controller */
maskon(Drsi[dev].vec);
cp = if_name(if_pca," tx");
if_pca->txproc = newproc(cp,512,if_tx,0,if_pca,NULL,0);
free(cp);
cp = if_name(if_pcb," tx");
if_pcb->txproc = newproc(cp,512,if_tx,0,if_pcb,NULL,0);
free(cp);
return 0;
}
/* Shut down iface */
static int
dr_stop(iface)
struct iface *iface;
{
uint16 dev;
dev = iface->dev;
if(dev & 1)
return 0;
dev >>= 1; /* Convert back into DRSI number */
/* Set 8259 interrupt mask (turn off interrupts) */
maskoff(Drsi[dev].vec);
/* Restore original interrupt vector */
setirq(Drsi[dev].vec, Drsi[dev].oldvec);
Drnbr--;
/* Force hardware reset */
write_scc(Drsi[dev].addr + CHANA + CTL,R9,FHWRES);
/* Reset the CTC */
(void) read_ctc(Drsi[dev].addr, Z8536_MICR);
write_ctc(Drsi[dev].addr, Z8536_MICR, 0x01);
return 0;
}
/* Send raw packet on DRSI card */
static int
dr_raw(
struct iface *iface,
struct mbuf **bpp
){
char kickflag;
struct drchan *hp;
int i_state;
dump(iface,IF_TRACE_OUT,*bpp);
iface->rawsndcnt++;
iface->lastsent = secclock();
hp = &Drchan[iface->dev];
i_state = dirps();
kickflag = (hp->sndq == NULL) & (hp->sndbuf == NULL);
/* clever! flag=1 if something in queue */
enqueue(&hp->sndq,bpp);
if(kickflag) /* simulate interrupt to xmit */
tx_fsm(hp); /* process interrupt */
restore(i_state);
return 0;
}
/* display DRSI Channel stats */
int
dodrstat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct drchan *hp0, *hp1;
int i;
for(i=0; i<DRMAX; i++){
hp0 = &Drchan[i];
hp1 = &Drchan[i+1];
i = Drchan[i].base;
printf("DRSI Board Statistics - N6TTO 112790.0\n");
printf("--------------------------------------\n");
printf("Channel - %s\n", hp0->iface->name);
printf("Rxints - %8ld Txints - %8ld Exints - %8ld\n",
hp0->rxints, hp0->txints, hp0->exints);
printf("Enqued - %8ld Crcerr - %8ld Aborts - %8ld\n",
hp0->enqueued, hp0->crcerr, hp0->aborts);
printf("RFrames - %8ld Rxovers - %8ld TooBig - %8ld\n",
hp0->rxframes, hp0->rovers, hp0->toobig);
printf("Txdefer - %8ld Txppers - %8ld Nomem - %8ld\n",
hp0->txdefers, hp0->txppersist, hp0->nomem);
printf("Tx state %8d Rx state %8d\n\n",hp0->tstate,hp0->rstate);
printf("Channel - %s\n", hp1->iface->name);
printf("Rxints - %8ld Txints - %8ld Exints - %8ld\n",
hp1->rxints, hp1->txints, hp1->exints);
printf("Enqued - %8ld Crcerr - %8ld Aborts - %8ld\n",
hp1->enqueued, hp1->crcerr, hp1->aborts);
printf("RFrames - %8ld Rxovers - %8ld TooBig - %8ld\n",
hp1->rxframes, hp1->rovers, hp1->toobig);
printf("Txdefer - %8ld Txppers - %8ld Nomem - %8ld\n",
hp1->txdefers, hp1->txppersist, hp1->nomem);
printf("Tx state %8d Rx state %8d\n",hp1->tstate,hp1->rstate);
}
return 0;
}
/* Subroutine to set kiss params in channel tables */
static int32
dr_ctl(iface,cmd,set,val)
struct iface *iface;
int cmd;
int set;
int32 val;
{
struct drchan *hp;
hp = &Drchan[iface->dev];
switch(cmd){
case PARAM_TXDELAY:
if(set)
hp->txdelay = val;
return hp->txdelay;
case PARAM_PERSIST:
if(set)
hp->persist = val;
return hp->persist;
case PARAM_SLOTTIME:
if(set)
hp->slotime = val;
return hp->slotime;
case PARAM_TXTAIL:
if(set)
hp->squeldelay = val;
return hp->squeldelay;
case PARAM_ENDDELAY:
if(set)
hp->enddelay = val;
return hp->enddelay;
case PARAM_SPEED:
return hp->speed;
}
return -1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -