📄 hs.c
字号:
/* Interface driver for the DRSI PCPA or the Eagle 8530 boards for the IBM PC
* connected to a WA4DSY 56kbps modem. Uses polling-loop transfers with
* interrupts disabled for maximum speed.
*
* This driver is a bit of a kludge. A DMA-driven card and driver (e.g.,
* the PI) is much better, but this is better than nothing if all you have
* is a "dumb" 8530 card.
*
*/
#include <stdio.h>
#include <dos.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "pktdrvr.h"
#include "netuser.h"
#include "hs.h"
#include "z8530.h"
#include "ax25.h"
#include "trace.h"
#include "nospc.h"
#include "proc.h"
#include "devparam.h"
static void flushrx(uint16 data);
static void hdlcparam(struct hdlc *hp);
static void hexint(struct hdlc *hp);
static void hrxint(struct hdlc *hp);
static int hs_stop(struct iface *iface);
static int hs_raw(struct iface *iface,struct mbuf **bpp);
static int32 hs_ctl(struct iface *,int cmd,int set,int32 val);
static void hstxoff(struct hdlc *hp);
static void hstxon(struct hdlc *hp);
static void htxint(struct hdlc *hp);
static void init_delay(void);
static void msdelay(void);
static struct hs Hs[NHS];
static INTERRUPT (*Hshandle[])() = { hs0vec };
static struct hdlc Hdlc[2*NHS];
static uint16 Nhs;
/* Master interrupt handler for the PC-100 card. All interrupts come
* here first, then are switched out to the appropriate routine.
*/
INTERRUPT (far *(hsint)(dev))()
int dev;
{
register char iv;
uint16 hsbase;
struct hs *hsp;
register struct hdlc *hp;
hsp = &Hs[dev];
hsp->ints++;
hsbase = hsp->addr;
#ifdef foo
outportb(hsbase+4,0x8+0x10); /* HIT EAGLE INTACK */
(void)inportb(hsbase+CHANA+CTL,R0);
outportb(hsbase+4,0x8); /***/
#endif
/* Read interrupt status from channel A */
while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
if(iv & CHARxIP){
/* Channel A Rcv Interrupt Pending */
hp = &Hdlc[2*dev];
hrxint(hp);
} else if(iv & CHATxIP){
/* Channel A Transmit Int Pending */
hp = &Hdlc[2*dev];
htxint(hp);
} else if(iv & CHAEXT){
/* Channel A External Status Int */
hp = &Hdlc[2*dev];
hexint(hp);
} else if(iv & CHBRxIP){
/* Channel B Rcv Interrupt Pending */
hp = &Hdlc[(2*dev)+1];
hrxint(hp);
} else if(iv & CHBTxIP){
/* Channel B Transmit Int Pending */
hp = &Hdlc[(2*dev)+1];
htxint(hp);
} else if(iv & CHBEXT){
/* Channel B External Status Int */
hp = &Hdlc[(2*dev)+1];
hexint(hp);
}
/* Reset interrupt pending state */
write_scc(hp->ctl,R0,RES_H_IUS);
outportb(hsbase+CHANA+CTL,0); /* Restore pointer to 0 */
outportb(hsbase+CHANB+CTL,0); /* Restore pointer to 0 */
}
outportb(hsbase+CHANA+CTL,0); /* Restore pointer to 0 */
outportb(hsbase+CHANB+CTL,0); /* Restore pointer to 0 */
return hsp->chain ? hsp->save.vec : NULL;
}
/* HDLC SIO External/Status interrupts
* The only one that can happen in this driver is a DCD change
*/
static void
hexint(hp)
register struct hdlc *hp;
{
struct mbuf *rcvbuf;
char *cp;
int cnt,data;
register int ctl;
ctl = hp->ctl;
data = hp->data;
hp->exints++;
/* Allocate a receive buffer */
if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct iface *))) == NULL){
/* Alloc failed; refuse to proceed */
hp->nomem++;
write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
write_scc(ctl,R0,RES_EXT_INT);
return;
}
/* Allow space for descriptor on front */
rcvbuf->data += sizeof(struct iface *);
cnt = 0;
/* Disable DCDIE bit so we can track changes in DCD */
write_scc(ctl,R15,0);
write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
flushrx(data);
while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
if(cnt > 4){
/* Good frame */
hp->good++;
/* Toss crc */
rcvbuf->cnt = cnt - 1;
net_route(hp->iface,&rcvbuf);
/* Replenish buffer */
rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct iface *));
}
/* Start new buffer */
if(rcvbuf == NULL)
break; /* alloc failed */
rcvbuf->data += sizeof(struct iface *);
}
write_scc(ctl,R0,RES_EXT_INT);
write_scc(ctl,R15,DCDIE); /* Re-enable DCD */
write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
/* Get rid of fragmentary buffer */
free_p(&rcvbuf);
}
static void
flushrx(data)
register uint16 data;
{
register int i = 5;
while(i-- != 0)
(void)inportb(data);
}
/* HDLC receiver interrupt handler.
* Not used in this driver
*/
static void
hrxint(hp)
register struct hdlc *hp;
{
}
/* HDLC transmit interrupt service routine
* Not used in this driver
*/
static void
htxint(hp)
register struct hdlc *hp;
{
}
/* (re)Initialize HDLC controller parameters */
static void
hdlcparam(hp)
register struct hdlc *hp;
{
register uint16 ctl;
int i_state;
/* Initialize 8530 channel for SDLC operation */
ctl = hp->ctl;
i_state = dirps();
#ifdef foo
switch(ctl & 2){
case CHANA:
write_scc(ctl,R9,CHRA); /* Reset channel A */
break;
case CHANB:
write_scc(ctl,R9,CHRB); /* Reset channel B */
break;
}
ppause(1L); /* Allow plenty of time for resetting */
#endif
/* Deselect interrupts for now */
write_scc(ctl,R1,0);
write_scc(ctl,R15,0);
/* X1 clock, SDLC mode, Sync modes enable, parity disable */
write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
/* CRC preset 1, NRZ encoding, no active on poll, flag idle,
* flag on underrun, no loop mode, 8 bit sync
*/
write_scc(ctl,R10,CRCPS|NRZ);
/* 8530 gets both tx and rx clock from modem.
* By default, TRxC = transmit clock, RTxC = receive clock
* (swapped 11 Feb 1990 to use new DRSI wiring) UNLESS
* the 'r' parameter is specified
*/
if(!hp->clkrev)
write_scc(ctl,R11,RCRTxCP | TCTRxCP);
else
write_scc(ctl,R11,RCTRxCP | TCRTxCP);
/* Note: baud rate generator not used */
/* Null out SDLC start address */
write_scc(ctl,R6,0);
/* SDLC flag */
write_scc(ctl,R7,FLAG);
/* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
* RTS off, TxCRC enable
*/
write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
/* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
* no address search, no inhibit sync chars, disable RX. Rx is
* started only by an actual DCD interrupt
*/
write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
/* Dummy interrupt vector
* (This probably isn't necessary)
*/
write_scc(ctl,R2,0);
/* Enable only the external interrupts (modem interrupts) since
* polling is used for all actual tx/rx operations
*/
write_scc(ctl,R1,EXT_INT_ENAB);
/* Enable only DCD interrupts */
write_scc(ctl,R15,DCDIE);
/* No reset, status low, master int enable, enable lower chain,
* no vector
*/
write_scc(ctl,R9,MIE|NV);
restore(i_state);
}
/* Attach a high speed iterface to the system
* argv[0]: hardware type, must be "hs"
* argv[1]: I/O address, e.g., "0x380"
* argv[2]: vector, e.g., "2"
* argv[3]: mode, must be "ax25"
* argv[4]: interface base label, e.g., "drsi0". Driver appends "a" and "b".
* argv[5]: receiver packet buffer size in bytes
* argv[6]: maximum transmission unit, bytes
* argv[7]: keyup delay, milliseconds
* argv[8]: persistence value, 0-255
* argv[9]: "r" to reverse sense of clock leads (optional)
*/
int
hs_attach(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct iface *if_hsa,*if_hsb;
struct hdlc *hp;
int dev;
char *cp;
if(Nhs >= NHS){
printf("Too many hs controllers\n");
return -1;
}
if(if_lookup(argv[4]) != NULL){
printf("Interface %s already exists\n",argv[4]);
return -1;
}
if(setencap(NULL,argv[3]) == -1){
printf("Unknown encapsulation %s\n",argv[3]);
return -1;
}
if(Mycall[0] == '\0'){
printf("set mycall first\n");
return -1;
}
dev = Nhs++;
/* Initialize hardware-level control structure */
Hs[dev].addr = htoi(argv[1]);
Hs[dev].vec = atoi(argv[2]);
if(strchr(argv[2],'c') != NULL)
Hs[dev].chain = 1;
else
Hs[dev].chain = 0;
/* Save original interrupt vector */
Hs[dev].save.vec = getirq(Hs[dev].vec);
/* Set new interrupt vector */
if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
printf("IRQ %u out of range\n",Hs[dev].vec);
Nhs--;
return -1;
}
/* Create interface structures and fill in details */
if_hsa = (struct iface *)callocw(1,sizeof(struct iface));
if_hsb = (struct iface *)callocw(1,sizeof(struct iface));
if_hsa->addr = if_hsb->addr = Ip_addr;
if_hsa->name = mallocw(strlen(argv[4])+2);
strcpy(if_hsa->name,argv[4]);
strcat(if_hsa->name,"a");
if_hsb->name = mallocw(strlen(argv[4])+2);
strcpy(if_hsb->name,argv[4]);
strcat(if_hsb->name,"b");
if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
if_hsa->dev = 2*dev;
if_hsb->dev = 2*dev + 1;
if_hsb->stop = if_hsa->stop = hs_stop;
if_hsb->raw = if_hsa->raw = hs_raw;
if_hsa->ioctl = if_hsb->ioctl = hs_ctl;
setencap(if_hsa,argv[3]);
setencap(if_hsb,argv[3]);
if(if_hsb->hwaddr == NULL)
if_hsb->hwaddr = mallocw(AXALEN);
memcpy(if_hsb->hwaddr,Mycall,AXALEN);
if(if_hsa->hwaddr == NULL)
if_hsa->hwaddr = mallocw(AXALEN);
memcpy(if_hsa->hwaddr,Mycall,AXALEN);
if_hsa->next = if_hsb;
if_hsb->next = Ifaces;
Ifaces = if_hsa;
write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
hp = &Hdlc[2*dev+1];
hp->ctl = Hs[dev].addr + CHANB + CTL;
hp->data = Hs[dev].addr + CHANB + DATA;
hp->bufsiz = atoi(argv[5]);
if(argc > 7)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -