/* test program for SDNet author: Henryk Richter Runs a number of essential operations on ENC28J60 modules connected to the SD slot of Vampire V2 (500/600) cards. */ #include #include #include #include #include #include #include #include #include "enc28j60.h" #include "enc28j60l.h" /* import lowlevel asm functions */ /* #include "crc32.h" */ #include "vampuuid.h" /*#define __NOLIBBASE__*/ #include #include #define INVALID_SDNET_UNIT 0x33 /* delay after changing SPI speed in us */ #define SPEED_DELAY 120 struct Library *VampireBase; /* */ /*u08 myprog = "sdnettest";*/ /* OUI = Commodore :-) */ u08 macaddr[6] = { 0x00,0x80,0x10,0x0b,0x0a,0xff }; #if 1 #define testlen 300 /* issue a DHCP request to increase the likelihood of received frames throughout the test */ u08 testframe[testlen] = { /* Ethernet(14) */ 0xff,0xff,0xff,0xff,0xff,0xff, /* broadcast */ 0x00,0x80,0x10,0x0b,0x0a,0xff, /* own MAC */ 0x08,0x00, /* Type IPv4 */ /* IPv4(20) */ /* IPv4 */ 0x45,0x00, /* VER/IHL, DSCP */ 0x01,0x1e, /* was 0d */ /* length 273 = 245+20 */ 0xA0,0x0A, /* id */ 0x00,0x00, /* flags, fragment offset */ 0xff, /* TTL (255 for DHCP) */ 0x11, /* UDP */ 0x00,0x00, /* header checksum */ 0,0,0,0, /* SRC IP */ 255,255,255,255,/* dest IP */ /* UDP(8) */ /* UDP */ 0x00,0x44, /* src port 68 */ 0x00,0x43, /* dest port 67 */ 0x01,0x0a, /* length including UDP header FIXME: CHANGE when payload changes */ 0x00,0x00, /* checksum */ /* BOOTP(245) */ /* BOOTP/DHCP */ 0x01, /* BOOT Request */ 0x01, /* HW Type Ethernet */ 0x06, /* HW Address length */ 0x00, /* hops */ 0xde,0xad,0xbe,0xef, /* transaction ID */ 0x00,0x02, /* seconds elapsed */ /* mandatory bootp stuff */ 0x00,0x00, /* flags */ 0x00,0x00,0x00,0x00, /* client IP */ 0x00,0x00,0x00,0x00, /* next server IP */ 0x00,0x00,0x00,0x00, /* relay agent IP */ 0x00,0x00,0x00,0x00, /* some more stuff */ 0x00,0x80,0x10,0x0b,0x0a,0xff, /* own MAC */ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, /* 10 bytes padding */ /* server name (64x0) */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* boot file name (128x0) */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* DHCP magic cookie */ 0x63,0x82,0x53,0x63, /* DHCP options */ 0x35,0x01,0x01, /* DHCP discover */ 0x37,0x04,0x01,0x03,0x06,0x0f, /* we want mask,router,DNS,Domain Name */ 0x3d,0x06, /* client identifier (3c would be vendor class) */ 0, 's','d','n','e','t', 0xff, /* end */ /* padding */ /* 0x00,0x00,0x00 */ }; #else #define testlen 98 u08 testframe[testlen] = { 0xff,0xff,0xff,0xff,0xff,0xff, /* broadcast */ 0x00,0x80,0x10,0x0b,0x0a,0xff, /* own MAC */ 0x08,0x00, /* Type IPv4 */ /* */ 0x45,0x00, /* VER, DSCP */ 0x00,0x54, /* length */ 0xA0,0x0A, /* id */ 0x00,0x00, /* flags, fragment offset */ 0x40, /* TTL */ 0x01, /* ICMP */ 0x00,0x00, /* header checksum */ 192,168,10,11, /* SRC IP */ 192,168,10,255,/* dest IP */ /* */ 0x08,0x00, /* Type, Code = ICMP Echo */ 0x00,0x00, /* Checksum */ 0xDE,0xAD, /* Identifier */ 0x00,0x01, /* SeqNum */ 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, }; /* 98 Bytes */ #endif unsigned char recvbuf[1530]; ULONG vres = (ULONG)-1; ULONG doquit = 0; u16 ip_checksum( u08 *, LONG ); u16 udp_checksum( u08 *, LONG ); /* SAS/C abort override */ int CXBRK(void ) { /* doquit = 1; */ return 0; } void __regargs __chkabort(void); void __regargs __chkabort(void) { if( SetSignal( 0, SIGBREAKF_CTRL_C ) & SIGBREAKF_CTRL_C ) { doquit = 1; printf("got ctrl-c\n"); } } /* global cleanup */ void cleanup(void) { if( VampireBase ) V_FreeExpansionPort( vres ); printf("cleaning up\n"); } /* communications test: try different clock dividers and poll revision */ ULONG sdnt_commtest( void ) { ULONG ret = 0; /* def: fail */ int speed = 10; /* try different SPI clock dividers */ int wait; u08 rev,rdy=0; /* soft reset cpu */ enc28j60_SetSPISpeed( (ULONG)speed ); enc28j60l_UMinDelay( SPEED_DELAY ); /* wait a little, */ enc28j60l_WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); /* enc28j60l_WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); enc28j60l_WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); enc28j60l_WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);*/ enc28j60l_UMinDelay( 4000 ); /* wait 4ms */ wait = 0xfff; while( wait-- > 0 ) { rdy = ESTAT_CLKRDY & enc28j60l_ReadOp(ENC28J60_READ_CTRL_REG, ESTAT ); if( rdy ) wait = 0; } enc28j60l_UMinDelay( 20 ); /* wait a little, */ if( !rdy ) { printf("Fail. Chip doesn`t respond ready.\n"); } else { rdy = enc28j60l_ReadRegByte(EREVID); if( rdy > 5 ) rdy++; } while( speed >= 0 ) { enc28j60_SetSPISpeed( (ULONG)speed ); enc28j60l_UMinDelay( SPEED_DELAY ); /* wait a little, */ enc28j60l_ReadRegByte(EREVID); rev = enc28j60l_ReadRegByte(EREVID); if( rev > 5 ) rev++; if( rdy ) /* best case: chip reported "ready" */ { if( rev != rdy ) { if( speed >= 2 ) printf("Fail. Different revision register reported by chip (%d vs %d at speed %d)\n",rdy,rev,speed); else printf("Note. Speed %d does not work properly with your card (but that was expected)\n",speed); } else { printf("Ok. Revision %d reported at speed %d\n",rev,speed); ret |= (1< 0) && (rev < 0x10 ) ) { printf("OK. got Chip rev %d at speed %d\n",rev,speed); ret |= (1<= 0 ; i-- ) { if( speeds & (1<ENVARC:sana2/v2expeth.config\n",clockdiv); #else printf(" echo \"SPISPEED=%d\" >ENVARC:sana2/sdnet.config\n",clockdiv); #endif } end: return ret; } /* IP header checksum input: IP header length (min. 20) output: checksum (also directly in IP header) */ u16 ip_checksum( u08 *buffer, LONG length ) { ULONG csum = 0; ULONG words,i; unsigned short *b2,*b3; if( length < 20 ) return 0; /* no checksum */ /* IPv4 header */ b2 = (unsigned short*)buffer; b2[5] = 0; words = ((ULONG)(buffer[0] & 0xf))<<1; /* IHL, def: 5 (32 bit words) */ /* sum up */ for( i=0,b3=b2 ; i < words ; i++ ) { csum += *b3++; } while( csum > 0xffff ) { csum = (csum&0xffff)+(csum>>16); } csum = (~csum)&0xffff; b2[5] = csum; /* store checksum */ return (u16)csum; } /* calculate UDP checksum - buffer supplied should point to IP packet, where src/dest/protocol are filled in length is in octets, including IPv4 header and UDP header input: IP packet including UDP header and content output: checksum (also directly in UDP header) */ u16 udp_checksum( u08 *buffer, LONG length ) { ULONG words,i; ULONG csum = 0; unsigned short *b2,*b3; if( length < 28 ) return 0; /* no checksum */ /* IPv4 pseudoheader (see for UDP length below) */ csum += *((unsigned short*)(&buffer[12])); /* src IP */ csum += *((unsigned short*)(&buffer[14])); /* src IP */ csum += *((unsigned short*)(&buffer[16])); /* dest IP */ csum += *((unsigned short*)(&buffer[18])); /* dest IP */ csum += (ULONG)buffer[9]; /* protocol */ /* location of UDP header */ words = ((ULONG)(buffer[0] & 0xf))<<2; /* IHL, def: 5 (32 bit words) */ b2 = (unsigned short*)(&buffer[words]); b2[3] = 0; /* clear checksum */ b3 = b2; csum += b2[2]; /* UDP length */ words = (length-words)>>1; /* total length - IP header */ for( i=0 ; i 0xffff ) { csum = (csum&0xffff)+(csum>>16); } csum = csum^0xffff; b3[3] = (u16)csum; /* store checksum */ return (u16)csum; }