/********************************************************************/ /* */ /* Packet driver for D-LINK DE600 ethernet controller */ /* */ /* Copyleft by P. Mayer, 1992 fortec - TU-Vienna IAEE */ /* All rights reserved */ /* */ /* (Pure-C) */ /********************************************************************/ #define LOCKMEM 0x1 #define LOCKALLO 0x2 #define LOCKFREE 0x4 #define LOCKMAIN 0x8 #define LOCKRES 0x10 #define LOCKREC 0x20 #define LOCKNET 0x40 #include #include #include #include #include #include "nicmem.h" #include "nicdrv.h" #include "pktqueue.h" #include "pktdrv.h" #include "cookie.h" #include "inetcust.h" #define noDEBUG #define noDEBUGINTR #define noDEBUGPKT #define Bconws(x) dpy = &x;while(*dpy)(Bconout(2,*dpy++)) char str[80]; char *dpy; PKTBUF PPKT[MAXPKT]; PKTPOOL PPOOL; extern char locked200; int retval; int term = 0; int good = 0; et_hdr header; int mode; void (interrupt *ihandler)(void) = NULL; extern void lance_interrupt(void); extern void lance_200interrupt(void); extern long *old200; int resetNIC(void); /* reset lance, init datastructures */ PKTPOOL *p_free; /* queue of free packets */ u_short freecnt; /* number of free packets */ procref ext_tab[8] = /* subfunction table */ { net_reset, net_open, net_release, net_send, net_getadr, net_info, (procref)net_pktalloc, net_pktfree }; PROTOCOL protos[MAXPROTOCOLS]; /* protocols to serve */ int protocols = 0; /* number of active protocols */ et_stat stat; /* statistics block */ /************************************************************* test for de600 ethernetadapter interface on cartridge port *************************************************************/ #define NIC_BASE 0xfa0000L typedef unsigned char byte; byte CurTxPage, Mode_RxPg; int RxPktLen, RxStartAdd, TxStartAdd, CurRxPage, our_type; byte our_address[6]; int last, LastTxStartAdd; #define WRITE (0x00 << 1) #define READ (0x01 << 1) #define STATUS (0x02 << 1) #define COMMAND (0x03 << 1) #define NUL_CMD (0x0c << 1) #define RX_LEN (0x05 << 1) #define TX_ADR (0x06 << 1) #define RW_ADR (0x07 << 1) #define WRITE_STROBE (0x08 << 1) #define RXEN (0x08) #define TXEN (0x04) #define LOOPBACK (0x0c) #define RX_NONE (0x00) #define RX_ALL (0x01) #define RX_BP (0x02) #define RX_MBP (0x03) #define RESET (0x80) #define STOP_RESET (0x00) #define RXBUSY 0x80 #define GOOD 0x40 #define RESET_FLAG 0x20 #define T16 0x10 #define TXBUSY 0x08 #define BFRSIZ 2048 #define RUNT 60 #define EADDR_LEN 6 #define HA13 0x20 #define PAGE_0 0x00 #define PAGE_1 0x08 #define PAGE_2 0x10 #define PAGE_3 0x18 #define delay() /* no delay needed for ST */ #define pause() /* defines for access to DE600 */ #define WRITE_SUB_FAST(value, cmd) \ x = *(int*)(base + (int)(((((int)value) << 5) & 0x1e0) + cmd)); \ x = *(int*)(base + (int)(last = (((((int)value) << 1) & 0x1e0) + ((cmd) ^ WRITE_STROBE)))); \ #define WRITE_SUB(value, cmd) \ x = *(int*)(base + (int)(((((int)value) << 5) & 0x1e0) + cmd | WRITE_STROBE)); \ delay(); \ x = *(int*)(base + (int)(((((int)value) << 5) & 0x1e0) + cmd)); \ delay(); \ x = *(int*)(base + (int)(((((int)value) << 1) & 0x1e0) + cmd)); \ delay(); \ x = *(int*)(base + (int)(last = ((((int)value) << 1) & 0x1e0) + cmd | WRITE_STROBE)); \ #define WRITE_SUPER_FAST(value, cmd) \ x = *(int*)(base + (int)(((((int)value) << 5)) + cmd)); \ x = *(int*)(base + (int)((((((int)value) << 1) & 0x1e0) + ((cmd) ^ WRITE_STROBE)))); \ #define READ_SUB(cmd) \ x = *(int*)(base + (int)(cmd | WRITE_STROBE)); \ delay(); \ x = *(int*)(base + (int)(cmd)); \ delay(); \ y = (*(int*)(base + (int)(cmd)) & 0xf0) ^ 0x80; \ x = *(int*)(base + (cmd | WRITE_STROBE)); \ delay(); \ y = (y >> 4) | ((*(int*)(base + (int)(last = (cmd | WRITE_STROBE))) & 0xf0) ^ 0x80); \ #define READ_STAT1 \ x = *(int*)(base + (int)STATUS); \ pause(); \ y = (*(int*)(base + (int)(STATUS))) ^ 0x80; \ x = *(int*)(base + (int)NUL_CMD); \ #define READ_STAT_FAST \ x = *(int*)(base + (int)STATUS); \ pause(); \ y = (*(int*)(base + (int)(STATUS))) ^ 0x80; \ #define READ_STAT(cmd) \ x = *(int*)(base + (int)(cmd | WRITE_STROBE)); \ delay(); \ x = *(int*)(base + (int)(cmd)); \ delay(); \ y = (*(int*)(base + (int)(cmd)) & 0xf0) ^ 0x80; \ x = *(int*)(base + (int)(NUL_CMD + WRITE_STROBE)); \ delay(); \ x = *(int*)(base + (int)(last = NUL_CMD)); \ delay(); \ #define READ_SUB_FAST(cmd) \ x = *(int*)(base + (int)(cmd)); \ x = (*(int*)(base + (int)(cmd))) & 0xf0; \ x >>= 4; \ y = *(int*)(base + (int)(cmd + WRITE_STROBE)); \ y = (((*(int*)(base + (cmd | WRITE_STROBE)) & 0xf0)) | x); \ y ^= 0x88; \ #define READ_SUPER_FAST(cmd) \ /* x = *(int*)(base + (int)(cmd));*/ \ x = (*(int*)(base + (int)(cmd))) & 0xf0; \ x >>= 4; \ /* y = *(int*)(base + (int)(cmd + WRITE_STROBE));*/ \ y = (((*(int*)(base + (cmd | WRITE_STROBE)) & 0xf0)) | x); \ y ^= 0x88; \ #define READ_HYPER_FAST(cmd) \ x = (*(int*)(base + (int)(cmd))) & 0xf0; \ x >>= 4; \ y = (((*(int*)(base + (cmd | WRITE_STROBE)) & 0xf0)) | x); \ y ^= 0x88; \ int copyEAD() { register byte *base = (byte*)NIC_BASE; register int x,y; int i; WRITE_SUB_FAST(0,RW_ADR); WRITE_SUB_FAST(HA13,RW_ADR); for(i = 0; i < EADDR_LEN;i++) { READ_SUB_FAST(READ); our_address[i] = y; } if( our_address[0] == 0x00 && our_address[1] == 0xde && our_address[2] == 0x15) { our_address[1] = 0x80; our_address[2] = 0xc8; /* our_address[3] &= 0x0f; our_address[3] |= 0x70; */ } else { return -1; } WRITE_SUB_FAST(0,RW_ADR); WRITE_SUB_FAST(HA13,RW_ADR); for(i = 0;i < EADDR_LEN;i++) { WRITE_SUB_FAST(our_address[i],WRITE); } x++; return 0; } int Check_DE600() { register byte *base = (byte*)NIC_BASE; register int x,y; x = *(int*)(base + NUL_CMD); delay(); WRITE_SUB(RESET,COMMAND); delay(); WRITE_SUB(STOP_RESET,COMMAND); delay(); READ_STAT(STATUS); x++; if(y == 0) return 0; else return -1; } int send_packet(byte *p_pkt, int pkt_len) { register byte *base = (byte*)NIC_BASE; register int x,y,TxStartAdd,val; int loop_cnt; void lnc_check(void); if(pkt_len < RUNT) pkt_len = RUNT; pkt_len = (pkt_len+1) & ~1; /* make sure min. size */ CurTxPage ^= 0x8; /* next free buffer */ TxStartAdd = (BFRSIZ - pkt_len) | ((int)CurTxPage << 8); WRITE_SUB_FAST(TxStartAdd & 0xff, RW_ADR); WRITE_SUB_FAST(TxStartAdd >> 8, RW_ADR); while(pkt_len--) { val = *p_pkt++; WRITE_SUPER_FAST(val,WRITE); } last = ( ( ( (int)(*(p_pkt-1)) << 1) & 0x1e0) + ((WRITE) ^ WRITE_STROBE)); for(loop_cnt = 0x4000;loop_cnt--;) { y = (*(int*)(base + (int)last)) ^ 0x80; if((y & TXBUSY) == 0) break; } LastTxStartAdd = TxStartAdd; WRITE_SUB_FAST(TxStartAdd & 0xff, TX_ADR); WRITE_SUB_FAST(TxStartAdd >> 8, TX_ADR); WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND); WRITE_SUB_FAST(Mode_RxPg | RXEN | TXEN, COMMAND); mode = TXEN | RXEN; x++; return pkt_len; } int test_mem() { register byte *base = (byte*)NIC_BASE; register int x,y,i; locked200 |= LOCKMEM; WRITE_SUB_FAST(0,RW_ADR); WRITE_SUB_FAST(0,RW_ADR); for(i = 0;i < 0x800;i++) { WRITE_SUB_FAST(i & 0xff,WRITE); } WRITE_SUB_FAST(0,RW_ADR); WRITE_SUB_FAST(0,RW_ADR); for(i=0;i<0x800;i++) { READ_SUB_FAST(READ); if((i & 0xff) != y) { Cconws("\r\nDE600 memory test error!!\r\n"); locked200 &= ~LOCKMEM; return -1; } } x++; locked200 &= ~LOCKMEM; return 0; } int resetNIC(void) { int copyEAD(void); int Check_DE600(void); int test_mem(void); void enable_rcv(void); CurRxPage = 0x20; Mode_RxPg = RX_BP | 0x20; CurTxPage = 0; if(Check_DE600()) return -1; if(test_mem()) return -1; if(copyEAD()) return -1; enable_rcv(); return 0; } void stopNIC(void) { register byte *base = (byte*)NIC_BASE; register int x; WRITE_SUB_FAST(Mode_RxPg, COMMAND); x++; } byte NICstatus() { register byte *base = (byte*)NIC_BASE; register int x,y; READ_STAT1; x++; return y; } void enable_rcv() { register byte *base = (byte*)NIC_BASE; register int x; WRITE_SUB_FAST(Mode_RxPg, COMMAND); WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND); mode = RXEN; x++; } int read_inf(void) { COOKIE *cookie; cookie = get_cookie(INETCUSTCOOKIE); if(!cookie || !cookie->val) return(0); return(1); } int net_info(int len, char *buf) { locked200 |= LOCKNET; if(!buf) { Mode_RxPg = (Mode_RxPg & 0xfc) | len; locked200 &= ~LOCKNET; return(0); } if(buf == (char *)1L) { resetNIC(); locked200 &= ~LOCKNET; return(0); } stat.st_free = freecnt; memcpy(buf,(char *)&stat,(size_t)len= MAXPROTOCOLS) return(EPROTAVAIL); new = -1; locked200 |= LOCKNET; if(!protocols) { if(net_reset() < 0) { locked200 &= ~LOCKNET; return(EINIT); } } for(i = 0; i < MAXPROTOCOLS; i++) { /* protocol already used */ if(protos[i].type == type) { locked200 &= ~LOCKNET; return(EPROTUSED); } if(protos[i].type == ET_UNUSED && new<0 ) new = i; /* find first free entry */ } if(new < 0) new = protocols; protocols++; protos[new].handler = handler; protos[new].recvd = 0; protos[new].sent = 0; protos[new].type = type; locked200 &= ~LOCKNET; return(new); } int net_release(int type) { int i; void stopNIC(void); if(!protocols) return(EPROTUSED); if(type == ET_UNUSED) return(EPROTUSED); for(i=0; i < MAXPROTOCOLS; i++) if(protos[i].type == type) break; if(i==MAXPROTOCOLS) { return(EPROTUSED); } locked200 |= LOCKNET; protocols--; if(!protocols) { stopNIC(); } protos[i].type = ET_UNUSED; protos[i].handler = NULL; locked200 &= ~LOCKNET; return(protocols); } int net_send(int len, char *buf) { register byte *base = (byte*)NIC_BASE; register long timeout; register int y; void lnc_check(void); byte NICstatus(void); void enable_rcv(void); #ifdef DEBI printf("netsend %lx length %d good = %d mode = %x\n",buf,len,good,mode); #endif if(!buf || !len || (buf < (char *)PPKT) || (buf > (char *)&PPOOL)) return(EPARAM); if(len < 60) len = 60; if(len > (int)sizeof(PACKET)) return(EPKTLEN); locked200 |= LOCKNET; timeout = clock() + 3*TIMEOUT; len = send_packet((byte*)buf,len); #ifdef DEBI printf("send done\n"); #endif locked200 &= ~LOCKNET; return(0); } int net_getadr(int len, char *buf) { if(len >= (int)sizeof(HADDR)) { buf[0] = our_address[0]; buf[1] = our_address[1]; buf[2] = our_address[2]; buf[3] = our_address[3]; buf[4] = our_address[4]; buf[5] = our_address[5]; return((int)sizeof(HADDR)); } return(0); } int net_reset(void) { int i,tmp; locked200 |= LOCKRES; for(i=0;i &PPKT[MAXPKT-1])) { Bconws("DLINKDRV: Packet out of bounds\r"); locked200 &= ~LOCKFREE; return(FALSE); } if(((long)p_pkt - (long)PPKT) % sizeof(PKTBUF)) { Bconws("DLINKDRV: Packet misaligned\r"); locked200 &= ~LOCKFREE; return(FALSE); } if(ap_putpkt(p_free,p_pkt)) { freecnt++; locked200 &= ~LOCKFREE; return(TRUE); } Bconws("DLINKDRV: Packet not freed\r"); locked200 &= ~LOCKFREE; return(FALSE); } /*******************************************************************/ /* read D-LINK function */ /*******************************************************************/ void lnc_check(void) { register byte *base = (byte*)NIC_BASE; register int x,y,i,ii,NICstate; int type, RxPktLen, loop; et_stat *et_stat; PKTBUF *pkt; byte * pb; locked200 |= LOCKREC; for(loop = 0;loop < 1;loop++) { x = *(int*)(base + (int)STATUS); y = *(int*)(base + (int)STATUS); x = *(int*)(base + (int)NUL_CMD); NICstate = y; if(NICstate & GOOD) { READ_SUPER_FAST(RX_LEN); RxPktLen = y; READ_SUPER_FAST(RX_LEN); RxPktLen += (y << 8); Mode_RxPg ^= 0x10; WRITE_SUB_FAST(Mode_RxPg, COMMAND); WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND); mode = RXEN; WRITE_SUB_FAST(0,RW_ADR); WRITE_SUB_FAST(CurRxPage >> 1,RW_ADR); CurRxPage ^= 0x10; RxPktLen -= 4; et_stat = &stat; et_stat->st_err = NICstate; et_stat->st_intr++; pb = (byte*)&header; for(i=0; i < 14;i++) { READ_SUPER_FAST(READ); *pb++ = y; } type = header.et_type; et_stat->st_received++; if(header.et_dest[0] != 0xff) { for(i = 0;i < MAXPROTOCOLS; i++) { if(protos[i].type == type) { /* must have one packet free */ if((pkt = ap_getpkt(type,p_free)) != 0) { freecnt--; memcpy((char*)pkt,(char*)&header,sizeof(et_hdr)); pb = pkt->et_data; for(ii=(int)sizeof(et_hdr); ii < RxPktLen; ii++) { READ_SUPER_FAST(READ); *pb++ = y; } if(protos[i].handler) { if(protos[i].handler(RxPktLen,(char *)pkt)) { et_stat->st_got++; protos[i].recvd++; } } else { /* free unused packet */ if(ap_putpkt(p_free,pkt)) freecnt++; break; } } } } } } else { WRITE_SUB_FAST(Mode_RxPg, COMMAND); WRITE_SUB_FAST(Mode_RxPg | RXEN, COMMAND); if(loop == 0) break; } if(NICstate & T16) { et_stat->st_xmiterr++; } } x++; locked200 &= ~LOCKREC; } int main() { COOKIE *cookie; int (*call)(void); long lance_install(void); Cconws("\r\nPacket driver V1.1 for Dlink DE600 "); cookie = get_cookie(PKTCOOKIE); if(cookie) { (long)call = ((long *)cookie->val)[NETRESET]; if(call() == 0) /* reset network */ Cconws("\r\nexisting driver reset\r\n"); else Cconws("\r\ncould not reset existing driver\r\n"); return 0; } if(!read_inf()) { Cconws("INETCUST not installed !!\r\n"); return 1; } else { if(net_reset() < 0) { Cconws("\r\nno DE600 detected !!\r\n"); return 1; } locked200 |= LOCKMAIN; if((int)Supexec(lance_install) < 0) { Cconws("\r\ncould not install handler !!\n"); return 1; } add_cookie(PKTCOOKIE,(long)ext_tab); Cconws("installed\r\n(c) pm FORTec 1992\r\n"); locked200 &= ~LOCKMAIN; Ptermres(_PgmSize,0); } return 0; } long lance_install() { void lnc_check(void); /* long **vblqueue = *(long***)0x456L; int vblnum = *(int*)0x454L; int i; for(i=1; i< vblnum;i++) if (*(vblqueue+i) == 0L) break; if(i< vblnum) { *(vblqueue+i) = (long*)lance_interrupt; ihandler = (void (interrupt *)())lnc_check; return 0; } else return -1; */ old200 = (long*)Setexc(69,lance_200interrupt); ihandler = (void (interrupt *)())lnc_check; /* old200 = *(long*)0x400; *(long*)0x400 = (long)lance_200interrupt;*/ return 0; }