OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [orpsocv2/] [sw/] [tests/] [ethmac/] [board/] [ethmac-ping.c] - Rev 438

Go to most recent revision | Compare with Previous | Blame | View Log

//////////////////////////////////////////////////////////////////////
////                                                              ////
////  Interrupt-driven Ethernet MAC test code for use on board    ////
////                                                              ////
////  Description                                                 ////
////  Controllable ping program - also responds to ARP requests   ////
////                                                              ////
////  Author(s):                                                  ////
////      - jb, jb@orsoc.se, with parts taken from Linux kernel   ////
////        open_eth driver.                                      ////
////                                                              ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
////                                                              ////
//// Copyright (C) 2009 Authors and OPENCORES.ORG                 ////
////                                                              ////
//// This source file may be used and distributed without         ////
//// restriction provided that this copyright statement is not    ////
//// removed from the file and that any derivative work contains  ////
//// the original copyright notice and the associated disclaimer. ////
////                                                              ////
//// This source file is free software; you can redistribute it   ////
//// and/or modify it under the terms of the GNU Lesser General   ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any   ////
//// later version.                                               ////
////                                                              ////
//// This source is distributed in the hope that it will be       ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
//// PURPOSE.  See the GNU Lesser General Public License for more ////
//// details.                                                     ////
////                                                              ////
//// You should have received a copy of the GNU Lesser General    ////
//// Public License along with this source; if not, download it   ////
//// from http://www.opencores.org/lgpl.shtml                     ////
////                                                              ////
//////////////////////////////////////////////////////////////////////
 
#include "cpu-utils.h"
#include "board.h"
#include "int.h"
#include "uart.h"
#include "ethmac.h"
#include "printf.h"
#include "eth-phy-mii.h"
 
volatile unsigned tx_done;
static int next_tx_buf_num;
 
//#define OUR_IP_BYTES 0xc0,0xa8,0x64,0x9b // 192.168.100.155
//#define OUR_IP_LONG 0xc0a8649b
 
//#define OUR_IP_BYTES 0xc0,0xa8,0x0,0x14 // 192.168.0.20
//#define OUR_IP_LONG 0xc0a80014
 
 
//#define OUR_IP_BYTES 0xc0,0xa8,0x1,0x22 // 192.168.1.34
//#define OUR_IP_LONG 0xc0a80122
 
#define OUR_IP_BYTES 0xc0,0xa8,0x1,0x2 // 192.168.1.2
#define OUR_IP_LONG 0xc0a80102
 
//#define OUR_IP_BYTES 0xac,0x1e,0x0,0x2 // 172.30.0.2
//#define OUR_IP_LONG 0xac1e0002
 
static char our_ip[4] = {OUR_IP_BYTES};
 
//#define DEST_IP_BYTES 0xc0,0xa8,0x64,0x69 // 192 .168.100.105
#define DEST_IP_BYTES 0xc0,0xa8,0x01,0x08 // 192 .168.1.8
//#define DEST_IP_BYTES 0xac,0x1e,0x0,0x01 // 172.30.0.1
 
#define BCAST_DEST_IP_BYTES 0xc0,0xa8,0x01,0xff // 192 .168.1.255
 
/* Functions in this file */
void ethmac_setup(void);
void oeth_printregs(void);
void ethphy_init(void);
void oeth_dump_bds();
/* Interrupt functions */
void oeth_interrupt(void);
static void oeth_rx(void);
static void oeth_tx(void);
/* Function to calculate checksum of ping responses we send */
unsigned short calculate_checksum(char* dats, unsigned int len) ;
 
// Global used to control whether we print out packets as we receive them
int print_packet_contents;
 
/* Let the ethernet packets use a space beginning here for buffering */
#define ETH_BUFF_BASE 0x01000000
 
 
#define RXBUFF_PREALLOC	1
#define TXBUFF_PREALLOC	1
//#undef RXBUFF_PREALLOC
//#undef TXBUFF_PREALLOC
 
/* The transmitter timeout
*/
#define TX_TIMEOUT	(2*HZ)
 
/* Buffer number (must be 2^n) 
*/
#define OETH_RXBD_NUM		64
#define OETH_TXBD_NUM		64
#define OETH_RXBD_NUM_MASK	(OETH_RXBD_NUM-1)
#define OETH_TXBD_NUM_MASK	(OETH_TXBD_NUM-1)
 
/* Buffer size 
*/
#define OETH_RX_BUFF_SIZE	2048
#define OETH_TX_BUFF_SIZE	2048
 
/* Buffer size  (if not XXBUF_PREALLOC 
*/
#define MAX_FRAME_SIZE		0x600
//#define MAX_FRAME_SIZE		2500
 
/* The buffer descriptors track the ring buffers.   
*/
struct oeth_private {
  //struct	sk_buff* rx_skbuff[OETH_RXBD_NUM];
  //struct	sk_buff* tx_skbuff[OETH_TXBD_NUM];
 
  unsigned short	tx_next;/* Next buffer to be sent */
  unsigned short	tx_last;/* Next buffer to be checked if packet sent */
  unsigned short	tx_full;/* Buffer ring fuul indicator */
  unsigned short	rx_cur;	/* Next buffer to be checked if packet received */
 
  oeth_regs	*regs;			/* Address of controller registers. */
  oeth_bd		*rx_bd_base;		/* Address of Rx BDs. */
  oeth_bd		*tx_bd_base;		/* Address of Tx BDs. */
 
  //	struct net_device_stats stats;
};
 
void oeth_printregs(void)
{
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  printf("Oeth regs: Mode Register : 0x%lx\n",
	 (unsigned long) regs->moder);          /* Mode Register */
  printf("Oeth regs: Interrupt Source Register 0x%lx\n", 
	 (unsigned long) regs->int_src);        /* Interrupt Source Register */
  printf("Oeth regs: Interrupt Mask Register 0x%lx\n",
	 (unsigned long) regs->int_mask);       /* Interrupt Mask Register */
  printf("Oeth regs: Back to Bak Inter Packet Gap Register 0x%lx\n",
	 (unsigned long) regs->ipgt);           /* Back to Bak Inter Packet Gap Register */
  printf("Oeth regs: Non Back to Back Inter Packet Gap Register 1 0x%lx\n",
	 (unsigned long) regs->ipgr1);          /* Non Back to Back Inter Packet Gap Register 1 */
  printf("Oeth regs: Non Back to Back Inter Packet Gap Register 2 0x%lx\n",
	 (unsigned long) regs->ipgr2);          /* Non Back to Back Inter Packet Gap Register 2 */
  printf("Oeth regs: Packet Length Register (min. and max.) 0x%lx\n",
	 (unsigned long) regs->packet_len);     /* Packet Length Register (min. and max.) */
  printf("Oeth regs: Collision and Retry Configuration Register 0x%lx\n",
	 (unsigned long) regs->collconf);       /* Collision and Retry Configuration Register */
  printf("Oeth regs: Transmit Buffer Descriptor Number Register 0x%lx\n",
	 (unsigned long) regs->tx_bd_num);      /* Transmit Buffer Descriptor Number Register */
  printf("Oeth regs: Control Module Mode Register 0x%lx\n",
	 (unsigned long) regs->ctrlmoder);      /* Control Module Mode Register */
  printf("Oeth regs: MII Mode Register 0x%lx\n",
	 (unsigned long) regs->miimoder);       /* MII Mode Register */
  printf("Oeth regs: MII Command Register 0x%lx\n",
	 (unsigned long) regs->miicommand);     /* MII Command Register */
  printf("Oeth regs: MII Address Register 0x%lx\n",
	 (unsigned long) regs->miiaddress);     /* MII Address Register */
  printf("Oeth regs: MII Transmit Data Register 0x%lx\n",
	 (unsigned long) regs->miitx_data);     /* MII Transmit Data Register */
  printf("Oeth regs: MII Receive Data Register 0x%lx\n",
	 (unsigned long) regs->miirx_data);     /* MII Receive Data Register */
  printf("Oeth regs: MII Status Register 0x%lx\n",
	 (unsigned long) regs->miistatus);      /* MII Status Register */
  printf("Oeth regs: MAC Individual Address Register 0 0x%lx\n",
	 (unsigned long) regs->mac_addr0);      /* MAC Individual Address Register 0 */
  printf("Oeth regs: MAC Individual Address Register 1 0x%lx\n",
	 (unsigned long) regs->mac_addr1);      /* MAC Individual Address Register 1 */
  printf("Oeth regs: Hash Register 0 0x%lx\n",
	 (unsigned long) regs->hash_addr0);     /* Hash Register 0 */
  printf("Oeth regs: Hash Register 1  0x%lx\n",
	 (unsigned long) regs->hash_addr1);     /* Hash Register 1 */    
 
}
 
static int last_char;
 
void spin_cursor(void)
{
#ifdef RTLSIM
  return;
#endif
  volatile unsigned int i; // So the loop doesn't get optimised away
  printf(" \r");
  if (last_char == 0)
    printf("/");
  else if (last_char == 1)
    printf("-");
  else if (last_char == 2)
    printf("\\");
  else if (last_char == 3)
    printf("|");
  else if (last_char == 4)
    printf("/");
  else if (last_char == 5)
    printf("-");
  else if (last_char == 6)
    printf("\\");
  else if (last_char == 7)
    {
      printf("|");
      last_char=-1;
    }
 
  last_char++;
 
  for(i=0;i<150000;i++);
 
}
 
#define PHYNUM 7
 
/* Scan the MIIM bus for PHYs */
void scan_ethphys(void)
{
  unsigned int phynum,regnum, i;
 
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  regs->miitx_data = 0;
 
  for(phynum=0;phynum<32;phynum++)
    {
      for (regnum=0;regnum<8;regnum++)
	{
	  printf("scan_ethphys: phy %d r%d ",phynum, regnum);
 
	  /* Now actually perform the read on the MIIM bus*/
	  regs->miiaddress = (regnum << 8) | phynum; /* Basic Control Register */
	  regs->miicommand = OETH_MIICOMMAND_RSTAT;
 
	  while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/
 
	  regs->miicommand = 0;
 
	  while(regs->miistatus & OETH_MIISTATUS_BUSY);
 
	  printf("%x\n",regs->miirx_data);
	}
    }
}
 
 
/* Scan the MIIM bus for PHYs */
void scan_ethphy(unsigned int phynum)
{
  unsigned int regnum, i;
 
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  regs->miitx_data = 0;
 
  for (regnum=0;regnum<32;regnum++)
    {
      printf("scan_ethphy%d: r%x ",phynum, regnum);
 
      /* Now actually perform the read on the MIIM bus*/
      regs->miiaddress = (regnum << 8) | phynum; /* Basic Control Register */
      regs->miicommand = OETH_MIICOMMAND_RSTAT;
 
      while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/
 
      regs->miicommand = 0;
 
      while(regs->miistatus & OETH_MIISTATUS_BUSY);
 
      printf("%x\n",regs->miirx_data);
    }
 
}
 
 
 
void ethmac_scanstatus(void)
{
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
 
  printf("Oeth: regs->miistatus %x regs->miirx_data %x\n",regs->miistatus, regs->miirx_data);
  regs->miiaddress = 0;
  regs->miitx_data = 0;
  regs->miicommand = OETH_MIICOMMAND_SCANSTAT;
  printf("Oeth: regs->miiaddress %x regs->miicommand %x\n",regs->miiaddress, regs->miicommand);  
  //regs->miicommand = 0; 
  volatile int i; for(i=0;i<1000;i++);
  while(regs->miistatus & OETH_MIISTATUS_BUSY) ;
  //spin_cursor(); 
  //printf("\r"); 
  //or32_exit(0);
}
 
void 
eth_mii_write(char phynum, short regnum, short data)
{
  static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
  regs->miiaddress = (regnum << 8) | phynum;
  regs->miitx_data = data;
  regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
  regs->miicommand = 0; 
  while(regs->miistatus & OETH_MIISTATUS_BUSY);
}
 
short 
eth_mii_read(char phynum, short regnum)
{
  static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
  regs->miiaddress = (regnum << 8) | phynum;
  regs->miicommand = OETH_MIICOMMAND_RSTAT;
  regs->miicommand = 0; 
  while(regs->miistatus & OETH_MIISTATUS_BUSY);
 
  return regs->miirx_data;
}
 
 
void
ethphy_reset(int phynum)
{
  eth_mii_write(phynum, MII_BMCR, 
		(eth_mii_read(phynum,MII_BMCR)|BMCR_RESET));
}
 
 
void
ethphy_reneg(int phynum)
{
  eth_mii_write(phynum, MII_BMCR, 
		(eth_mii_read(phynum,MII_BMCR)|BMCR_ANRESTART));
}
 
void 
ethphy_set_10mbit(int phynum)
{
  // Hardset PHY to just use 10Mbit mode
  short cr = eth_mii_read(phynum, MII_BMCR);
  cr &= ~BMCR_ANENABLE; // Clear auto negotiate bit
  cr &= ~BMCR_SPEED100; // Clear fast eth. bit
  eth_mii_write(phynum, MII_BMCR, cr);
}
 
void 
ethphy_set_100mbit(int phynum)
{
  // Hardset PHY to just use 10Mbit mode
  short cr = eth_mii_read(phynum, MII_BMCR);
  cr &= !BMCR_ANENABLE; // Clear auto negotiate bit
  cr |= BMCR_SPEED100; // Clear fast eth. bit
  eth_mii_write(phynum, MII_BMCR, cr);
}
 
void 
ethphy_set_autoneg(int phynum)
{
  // Hardset PHY to just use 10Mbit mode
  short cr = eth_mii_read(phynum, MII_BMCR);
  cr |= BMCR_ANENABLE; // Clear auto negotiate bit
  eth_mii_write(phynum, MII_BMCR, cr);
}
 
 
 
void m88e111_config_init(int phyaddr)
{
  short ctl;
  short adv;
#if 1
  // Soft reset
  eth_mii_write(phyaddr, MII_BMCR, BMCR_RESET);
  while(eth_mii_read(phyaddr, MII_BMCR) & BMCR_RESET);
 
  ctl = eth_mii_read(phyaddr, MII_BMCR);
  ctl &= ~(BMCR_SPD2);  
  eth_mii_write(phyaddr, MII_BMCR, ctl);
 
  eth_mii_read(phyaddr, MII_ADVERTISE);
  adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_1000XFULL
	   |ADVERTISE_1000XHALF | ADVERTISE_1000XPAUSE |
	   ADVERTISE_1000XPSE_ASYM);
  adv |= ADVERTISE_10HALF;
  adv |= ADVERTISE_10FULL;
  adv |= ADVERTISE_100HALF;
  adv |= ADVERTISE_100FULL;
  eth_mii_write(phyaddr, MII_ADVERTISE, adv);
  // Disable gigabit???
  adv = eth_mii_read(phyaddr, MII_M1011_PHY_SPEC_CONTROL);
  adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
	   MII_1000BASETCONTROL_HALFDUPLEXCAP);
  eth_mii_write(phyaddr, MII_M1011_PHY_SPEC_CONTROL, adv);
  // Even more disable gigabit?!
  adv = eth_mii_read(phyaddr, MII_CTRL1000);
  adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
  eth_mii_write(phyaddr, MII_CTRL1000, adv);
 
  // Restart autoneg
  printf("Resetting phy...\n");  
  eth_mii_write(phyaddr, MII_BMCR, BMCR_RESET);
  ctl = eth_mii_read(phyaddr, MII_BMCR);
  ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
  eth_mii_write(phyaddr, MII_BMCR, ctl);
#endif
 
#if 0
  // Adapted from kernel: drivers/net/phy/marvell.c
  // Soft reset
  eth_mii_write(phyaddr, MII_BMCR, BMCR_RESET);
 
  eth_mii_write(phyaddr, 0x1d, 0x1f);
  eth_mii_write(phyaddr, 0x1e, 0x200c);
  eth_mii_write(phyaddr, 0x1d, 0x5);
  eth_mii_write(phyaddr, 0x1e, 0);
  eth_mii_write(phyaddr, 0x1e, 0x100);
#define MII_M1011_PHY_SCR		0x10
#define MII_M1011_PHY_SCR_AUTO_CROSS	0x0060
  eth_mii_write(phyaddr, MII_M1011_PHY_SCR,
		MII_M1011_PHY_SCR_AUTO_CROSS);
#define MII_M1111_PHY_LED_CONTROL	0x18
#define MII_M1111_PHY_LED_DIRECT	0x4100
  eth_mii_write(phyaddr, MII_M1111_PHY_LED_CONTROL,
		MII_M1111_PHY_LED_DIRECT);
 
  adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | 
	   ADVERTISE_PAUSE_ASYM);
  adv |= ADVERTISE_10HALF;
  adv |= ADVERTISE_10FULL;
  adv |= ADVERTISE_100HALF;
  adv |= ADVERTISE_100FULL;
  adv |= ADVERTISE_PAUSE_CAP;
  adv |= ADVERTISE_PAUSE_ASYM;
  eth_mii_write(phyaddr, MII_ADVERTISE, adv);
 
 
  ctl = eth_mii_read(phyaddr, MII_BMCR);
  ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
  eth_mii_write(phyaddr, MII_BMCR, ctl);  
 
#endif
 
#if 0
  ctl = eth_mii_read(phyaddr, MII_BMCR);
  ctl &= ~(BMCR_ANENABLE); // Disable autoneg...
  // Try forcing config
  ctl = BMCR_SPEED100 | BMCR_FULLDPLX;
  eth_mii_write(phyaddr, MII_BMCR, ctl);
 
 
 
 
#endif
 
}
 
 
void ethphy_print_status(int phyaddr)
{
  short regnum, ctl;
  int bitnum;
  int bitset;
  printf("phyaddr %d\n",phyaddr);
  for  (regnum = 0;regnum<16; regnum++)
    {
      ctl = eth_mii_read(phyaddr, regnum);
      printf("\treg 0x%x: ", regnum);
      switch(regnum)
	{
	case 0:
	  printf("basic control\n");
	  for(bitnum = 0; bitnum<16;bitnum++)
	    {
	      bitset = !!(ctl & (1<<bitnum));
	      switch(bitnum)
		{
		case 0:
		  printf("\t\tbit%d:\t%d \t(disable transmitter)\n",bitnum,bitset);
		  break;
		case 6:
		  printf("\t\tbit%d:\t%d \t(msb speed (1000))\n",bitnum,bitset);
		  break;
		case 7:
		  printf("\t\tbit%d:\t%d \t(collision test)\n",bitnum,bitset);
		  break;
		case 8:
		  printf("\t\tbit%d:\t%d \t(duplex mode)\n",bitnum,bitset);
		  break;
		case 9:
		  printf("\t\tbit%d:\t%d \t(restart autoneg)\n",bitnum,bitset);
		  break;
		case 10:
		  printf("\t\tbit%d:\t%d \t(isloate)\n",bitnum,bitset);
		  break;
		case 11:
		  printf("\t\tbit%d:\t%d \t(power down)\n",bitnum,bitset);
		  break;
		case 12:
		  printf("\t\tbit%d:\t%d \t(autoneg enable)\n",bitnum,bitset);
		  break;
		case 13:
		  printf("\t\tbit%d:\t%d \t(speed select)\n",bitnum,bitset);
		  break;
		case 14:
		  printf("\t\tbit%d:\t%d \t(loop back)\n",bitnum,bitset);
		  break;
		case 15:
		  printf("\t\tbit%d:\t%d \t(reset)\n",bitnum,bitset);
		  break;
		default:
		  break;
		}
	    }
	  break;
	case 1:
	  printf("basic status\n");
	  for(bitnum = 0; bitnum<16;bitnum++)
	    {
	      bitset = !!(ctl & (1<<bitnum));
	      switch(bitnum)
		{
		case 0:
		  printf("\t\tbit%d:\t%d \t(extend capability)\n",bitnum,bitset);
		  break;
		case 1:
		  printf("\t\tbit%d:\t%d \t(jabber detect)\n",bitnum,bitset);
		  break;
		case 2:
		  printf("\t\tbit%d:\t%d \t(link status)\n",bitnum,bitset);
		  break;
		case 3:
		  printf("\t\tbit%d:\t%d \t(autoneg capability)\n",bitnum,bitset);
		  break;
		case 4:
		  printf("\t\tbit%d:\t%d \t(remote fault)\n",bitnum,bitset);
		  break;
		case 5:
		  printf("\t\tbit%d:\t%d \t(autoneg complete)\n",bitnum,bitset);
		  break;
		case 6:
		  printf("\t\tbit%d:\t%d \t(no preamble)\n",bitnum,bitset);
		  break;
		case 11:
		  printf("\t\tbit%d:\t%d \t(10base-t half dup.)\n",bitnum,bitset);
		  break;
		case 12:
		  printf("\t\tbit%d:\t%d \t(10base-t full dup.)\n",bitnum,bitset);
		  break;
		case 13:
		  printf("\t\tbit%d:\t%d \t(100base-t half dup.)\n",bitnum,bitset);
		  break;
		case 14:
		  printf("\t\tbit%d:\t%d \t(100base-t full dup.)\n",bitnum,bitset);
		  break;
		case 15:
		  printf("\t\tbit%d:\t%d \t(100base-t4)\n",bitnum,bitset);
		  break;
		default:
		  break;
 
		}
	    }
	  break;
	case 4:
	  printf("autoneg advertise reg\n");
	  for(bitnum = 0; bitnum<16;bitnum++)
	    {
	      bitset = !!(ctl & (1<<bitnum));
	      switch(bitnum)
		{
		case 5:
		  printf("\t\tbit%d:\t%d \t(10mbps cap.)\n",bitnum,bitset);
		  break;
		case 6:
		  printf("\t\tbit%d:\t%d \t(10base-5 full dup. cap.)\n",bitnum,bitset);
		  break;
		case 7:
		  printf("\t\tbit%d:\t%d \t(100base-tx cap.)\n",bitnum,bitset);
		  break;
		case 8:
		  printf("\t\tbit%d:\t%d \t(100base-tx full dup. cap.)\n",bitnum,bitset);
		  break;
		case 9:
		  printf("\t\tbit%d:\t%d \t(100base-t4 cap.)\n",bitnum,bitset);
		  break;
		case 10:
		  printf("\t\tbit%d:\t%d \t(pause cap.)\n",bitnum,bitset);
		  break;
		case 13:
		  printf("\t\tbit%d:\t%d \t(remote fault sup.)\n",bitnum,bitset);
		  break;
		case 15:
		  printf("\t\tbit%d:\t%d \t(next page cap.)\n",bitnum,bitset);
		  break;
 
		default:
		  break;
		}
	    }
	  break;
	case 5:
	  printf("autoneg link partner ability\n");
	  for(bitnum = 0; bitnum<16;bitnum++)
	    {
	      bitset = !!(ctl & (1<<bitnum));
	      switch(bitnum)
		{
		case 5:
		  printf("\t\tbit%d:\t%d \t(10mbps cap.)\n",bitnum,bitset);
		  break;
		case 6:
		  printf("\t\tbit%d:\t%d \t(10base-5 full dup. cap.)\n",bitnum,bitset);
		  break;
		case 7:
		  printf("\t\tbit%d:\t%d \t(100base-tx cap.)\n",bitnum,bitset);
		  break;
		case 8:
		  printf("\t\tbit%d:\t%d \t(100base-tx full dup. cap.)\n",bitnum,bitset);
		  break;
		case 9:
		  printf("\t\tbit%d:\t%d \t(100base-t4 cap.)\n",bitnum,bitset);
		  break;
		case 10:		  
		  printf("\t\tbit%d:\t%d \t(pause cap bit0)\n",bitnum,bitset);
		  break;
		case 11:
		  printf("\t\tbit%d:\t%d \t(pause cap bit1)\n",bitnum,bitset);
		  break;
 
		case 13:
		  printf("\t\tbit%d:\t%d \t(remote fault sup.)\n",bitnum,bitset);
		  break;
		case 14:
		  printf("\t\tbit%d:\t%d \t(acknowledge)\n",bitnum,bitset);
		  break;
		case 15:
		  printf("\t\tbit%d:\t%d \t(next page cap.)\n",bitnum,bitset);
		  break;
 
		default:
		  break;
		}
	    }
	  break;
	case 9:
	  printf("1000mbit advertise\n");
	  for(bitnum = 0; bitnum<16;bitnum++)
	    {
	      bitset = !!(ctl & (1<<bitnum));
	      switch(bitnum)
		{
		case 8:
		  printf("\t\tbit%d:\t%d \t(1000base-t half dup)\n",bitnum,bitset);
		  break;
		case 9:
		  printf("\t\tbit%d:\t%d \t(1000base-t full dup)\n",bitnum,bitset);
		  break;
		default:
		  break;
		}
	    }
	  break;	   
	case 0xf:
	  printf("extended status\n");
	  for(bitnum = 0; bitnum<16;bitnum++)
	    {
	      bitset = !!(ctl & (1<<bitnum));
	      switch(bitnum)
		{
		case 12:
		  printf("\t\tbit%d:\t%d \t(1000mb half dup.)\n",bitnum,bitset);
		  break;		  
		case 13:
		  printf("\t\tbit%d:\t%d \t(1000mb full dup.)\n",bitnum,bitset);
		  break;
		default:
		  break;
		}
	    }
	  break;
	  /*	case 1:
	  for(bitnum = 0; bitnum<16;bitnum++)
	  {
	  bitset = !!(ctl & (1<<bitnum));
	  switch(bitnum)
	  {
	  case 0:
	  printf("\t\tbit%d:\t%d \t()\n",bitnum,bitset);
	  break;
	  default:
	  break;
	  }
	  }
	  break;
	  */
	default:
	  printf("ignored\n");
	  break;
	}
    }	  
 
 
 
}
 
void ethphy_init(void)
{
 
  /* Init the Alaska 88E1111 Phy */
  char alaska88e1111_ml501_phynum = 0x7;
  m88e111_config_init(alaska88e1111_ml501_phynum);
 
  return;
 
  /* Init, reset */
  short ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR);
  ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
  ctl |= BMCR_SPEED100; // 100MBit
  ctl |= BMCR_FULLDPLX; // Full duplex
  eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl);
 
  // Setup Autoneg
  short adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_ADVERTISE);
  adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_1000XFULL
	   |ADVERTISE_1000XHALF | ADVERTISE_1000XPAUSE |
	   ADVERTISE_1000XPSE_ASYM);
  adv |= ADVERTISE_10HALF;
  adv |= ADVERTISE_10FULL;
  adv |= ADVERTISE_100HALF;
  adv |= ADVERTISE_100FULL;
  eth_mii_write(alaska88e1111_ml501_phynum, MII_ADVERTISE, adv);
  // Disable gigabit???
  adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL);
  adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
	   MII_1000BASETCONTROL_HALFDUPLEXCAP);
  eth_mii_write(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL, adv);
  // Even more disable gigabit?!
  adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_CTRL1000);
  adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
  eth_mii_write(alaska88e1111_ml501_phynum, MII_CTRL1000, adv);
 
  // Restart autoneg
  printf("Resetting phy...\n");  
  ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR);
  ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
  eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl);
 
  printf("\nOeth: PHY control reg: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR));
  printf("Oeth: PHY control reg: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_BMSR));
  printf("Oeth: PHY id0: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_PHYSID1));
  printf("Oeth: PHY id1: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_PHYSID2));
  printf("Oeth: PHY adv: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_ADVERTISE));
  printf("Oeth: PHY lpa: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_LPA));
  printf("Oeth: PHY physpec: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL));
  printf("Oeth: PHY expansion: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_EXPANSION ));
  printf("Oeth: PHY ctrl1000: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_CTRL1000));
  printf("Oeth: PHY stat1000: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_STAT1000));
  printf("Oeth: PHY estatus: 0x%.4x\n",
	 eth_mii_read(alaska88e1111_ml501_phynum, MII_ESTATUS));
 
 
}
 
 
void ethmac_setup(void)
{
  // from arch/or32/drivers/open_eth.c
  volatile oeth_regs *regs;
 
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  /*printf("\nbefore reset\n\n");
  oeth_printregs();*/
 
  /* Reset MII mode module */
  regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */
  regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */
  regs->miimoder = 0x64; /* Clock divider for MII Management interface */
 
  /* Reset the controller.
  */
  regs->moder = OETH_MODER_RST;	/* Reset ON */
  regs->moder &= ~OETH_MODER_RST;	/* Reset OFF */
 
  //printf("\nafter reset\n\n");
  //oeth_printregs();
 
  /* Setting TXBD base to OETH_TXBD_NUM.
  */
  regs->tx_bd_num = OETH_TXBD_NUM;
 
 
  /* Set min/max packet length 
  */
  //regs->packet_len = 0x00400600;
  regs->packet_len = (0x0040 << 16) | (MAX_FRAME_SIZE & 0xffff);
 
  /* Set IPGT register to recomended value 
  */
  regs->ipgt = 0x12;
 
  /* Set IPGR1 register to recomended value 
  */
  regs->ipgr1 = 0x0000000c;
 
  /* Set IPGR2 register to recomended value 
  */
  regs->ipgr2 = 0x00000012;
 
  /* Set COLLCONF register to recomended value 
  */
  regs->collconf = 0x000f003f;
 
  /* Set control module mode 
  */
#if 0
  regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW;
#else
  regs->ctrlmoder = 0;
#endif
 
  /* Clear MIIM registers */
  regs->miitx_data = 0;
  regs->miiaddress = 0;
  regs->miicommand = 0;
 
  regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1;
  regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | 
    ETH_MACADDR4 << 8 | ETH_MACADDR5;
 
  /* Clear all pending interrupts 
  */
  regs->int_src = 0xffffffff;
 
  /* Promisc, IFG, CRCEn
  */
  regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | 
    OETH_MODER_CRCEN | OETH_MODER_FULLD;
 
  /* Enable interrupt sources.
  */
 
  regs->int_mask = OETH_INT_MASK_TXB 	| 
    OETH_INT_MASK_TXE 	| 
    OETH_INT_MASK_RXF 	| 
    OETH_INT_MASK_RXE 	|
    OETH_INT_MASK_BUSY 	|
    OETH_INT_MASK_TXC	|
    OETH_INT_MASK_RXC;
 
  // Buffer setup stuff
  volatile oeth_bd *tx_bd, *rx_bd;
  int i,j,k;
 
  /* Initialize TXBD pointer
  */
  tx_bd = (volatile oeth_bd *)OETH_BD_BASE;
 
  /* Initialize RXBD pointer
  */
  rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
 
  /* Preallocated ethernet buffer setup */
  unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */
 
  // Setup TX Buffers
  for(i = 0; i < OETH_TXBD_NUM; i++) {
    //tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
    tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC;
    tx_bd[i].addr = mem_addr;
    mem_addr += OETH_TX_BUFF_SIZE;
  }
  tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
 
  // Setup RX buffers
  for(i = 0; i < OETH_RXBD_NUM; i++) {
    rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ
    rx_bd[i].addr = mem_addr;
    mem_addr += OETH_RX_BUFF_SIZE;
  }
  rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps
 
  /* Enable receiver and transmiter 
  */
  regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
 
  next_tx_buf_num = 0; // init tx buffer pointer
 
  return;
}
 
void
ethmac_togglehugen(void)
{
 
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  regs->moder ^= OETH_MODER_HUGEN; // Toggle huge packet enable
 
  if (regs->moder & OETH_MODER_HUGEN) // If we just enabled huge packets
    regs->packet_len = (0x0040 << 16) | (((64*1024)-4) & 0xffff);
  else
    // back to normal
    regs->packet_len = (0x0040 << 16) | (MAX_FRAME_SIZE & 0xffff);
 
  return;
 
}
 
void 
oeth_reset_tx_bd_pointer(void)
{
  printf("Resetting TX BD pointer\n");
  // from arch/or32/drivers/open_eth.c
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  // Toggle TXEN bit, resetting TX BD number
  regs->moder &= OETH_MODER_TXEN;
  regs->moder |= OETH_MODER_TXEN;
 
  next_tx_buf_num = 0; // init tx buffer pointer
 
}
 
 
 
/* Find the next available transmit buffer */
struct oeth_bd* get_next_tx_bd()
{
 
  int i;
  volatile oeth_bd *tx_bd;
  tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/
 
  /* Go through the TX buffs, search for unused one */
  for(i = next_tx_buf_num; i < OETH_TXBD_NUM; i++) {
 
    if(!(tx_bd[i].len_status & OETH_TX_BD_READY)) /* Looking for buffer NOT ready for transmit. ie we can manipulate it */
      {
	if (print_packet_contents)
	  printf("Oeth: Using TX_bd at 0x%lx\n",(unsigned long)&tx_bd[i]);
 
	if (next_tx_buf_num == OETH_TXBD_NUM-1) next_tx_buf_num = 0;
	else next_tx_buf_num++;
 
	return (struct oeth_bd*) &tx_bd[i];
      }
 
    if ((i == OETH_TXBD_NUM-1) && (next_tx_buf_num != 0)) 
      i = 0;
 
  }
 
  printf("No free tx buffers\n");
  /* Set to null our returned buffer */
  tx_bd = (volatile oeth_bd *) 0;
  return (struct oeth_bd*) tx_bd;
 
}
 
/* print packet contents */
static void
oeth_print_packet(unsigned long add, int len)
{
 
  int truncate = (len > 256);
  int length_to_print = truncate ? 256 : len;
 
  int i;
  printf("\nipacket: add = %lx len = %d\n", add, len);
  for(i = 0; i < length_to_print; i++) {
    if(!(i % 8))
      printf(" ");
    if(!(i % 16))
      printf("\n");
    printf(" %.2x", *(((unsigned char *)add) + i));
 
  }
  printf("\n");
 
  if (truncate)
    printf("\ttruncated....\n");
 
}
 
/* Setup buffer descriptors with data */
/* length is in BYTES */
void tx_packet(void* data, int length)
{
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  volatile oeth_bd *tx_bd;
  volatile int i;
 
 
  tx_bd = (volatile oeth_bd *)OETH_BD_BASE;
  tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num];
 
  /*if((tx_bd = (volatile oeth_bd *) get_next_tx_bd()) == NULL)
  {
  printf("No more TX buffers available\n");
  return;
  }
  */
  if (print_packet_contents)
    printf("Oeth: Using TX_bd buffer address: 0x%lx\n",(unsigned long) tx_bd->addr);
 
  /* Clear all of the status flags.
  */
  tx_bd->len_status &= ~OETH_TX_BD_STATS;
 
  /* If the frame is short, tell CPM to pad it.
  */
#define ETH_ZLEN        60   /* Min. octets in frame sans FCS */
  if (length <= ETH_ZLEN)
    tx_bd->len_status |= OETH_TX_BD_PAD;
  else
    tx_bd->len_status &= ~OETH_TX_BD_PAD;
 
  //printf("Oeth: Copying %d bytes from 0x%lx to TX_bd buffer at 0x%lx\n",length,(unsigned long) data,(unsigned long) tx_bd->addr);
 
  /* Copy the data into the transmit buffer, byte at a time */
  char* data_p = (char*) data;
  char* data_b = (char*) tx_bd->addr;
  for(i=0;i<length;i++)
    {
      data_b[i] = data_p[i];
    }
  //printf("Oeth: Data copied to buffer\n");
 
  /* Set the length of the packet's data in the buffer descriptor */
  tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | 
    ((length&0xffff) << 16);
 
  //oeth_print_packet(tx_bd->addr, (tx_bd->len_status >> 16));
 
  /* Send it on its way.  Tell controller its ready, interrupt when sent
  * and to put the CRC on the end.
  */
  tx_bd->len_status |= (OETH_TX_BD_READY  | OETH_TX_BD_CRC | OETH_TX_BD_IRQ);
 
  next_tx_buf_num = (next_tx_buf_num + 1) & OETH_TXBD_NUM_MASK;
 
  return;
 
 
}  
 
/* enable RX, loop waiting for arrived packets and print them out */
void oeth_monitor_rx(void)
{
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  /* Set RXEN in MAC MODER */
  regs->moder = OETH_MODER_RXEN | regs->moder;  
 
 
  volatile oeth_bd *rx_bd; 
  rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
 
  volatile int i;
 
  for(i=0;i<OETH_RXBD_NUM;i++)
    {
      if (!(rx_bd[i].len_status & OETH_RX_BD_EMPTY)) /* Not empty */
	{
	  // Something in this buffer!
	  printf("Oeth: RX in buf %d - len_status: 0x%lx\n",i, rx_bd[i].len_status);
	  oeth_print_packet(rx_bd[i].addr, rx_bd[i].len_status >> 16);
	  /* Clear recieved bit */
	  rx_bd[i].len_status |=  OETH_RX_BD_EMPTY;	      
	  printf("\t end of packet\n\n");
	}
    }
}
 
/* Print out all buffer descriptors */
void oeth_dump_bds()
{
  unsigned long* bd_base = (unsigned long*) OETH_BD_BASE;
 
  int i;
  for(i=0;i<OETH_TXBD_NUM;i++)
    {
      printf("oeth: tx_bd%d: len_status: %lx ",i,*bd_base++);
      printf("addr: %lx\n", *bd_base++);
    }
 
  for(i=0;i<OETH_RXBD_NUM;i++)
    {
      printf("oeth: rx_bd%d: len_status: %lx ",i,*bd_base++);
      printf("addr: %lx\n", *bd_base++);
    }
 
}
 
 
 
char broadcast_ping_packet[] =  {
  0xff,0xff,0xff,0xff,0xff,0xff, /*SRC MAC*/
  0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/
  0x08,0x00,
  0x45,
  0x00,
  //  0x00,0x54, /* length */
  0x01,0x1c, /* length */
  0x00,0x00,
  0x40,
  0x00,
  0x40,
  0x01,
  0xb5,0x8f,
  OUR_IP_BYTES, /* Source IP */
  BCAST_DEST_IP_BYTES, /* Dest. IP */
  /* ICMP Message body */
  0x08,0x00,0x7d,0x65,0xa7,0x20,0x00,0x01,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
  15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
  40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,
  65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,
  90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,
  111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,
  130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,
  149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,
  168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,
  187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,
  206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,
  225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,
  244,245,246,247,248,249,250,251,252,253,254,255};
 
 
char big_ping_packet[] =  {
  0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/
  //0xff,0xff,0xff,0xff,0xff,0xff, /*SRC MAC*/
  0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/
  0x08,0x00,
  0x45,
  0x00,
  0x05,0xdc, /* length */
  0x00,0x00,
  0x40,
  0x00,
  0x40,
  0x01,
  0xea,0xcb,   /* Header checksum */
  OUR_IP_BYTES, /* Source IP */
  DEST_IP_BYTES, /* Dest. IP */
  /* ICMP Message body */
  0x08,0x00, /* Type */
  0x04,0x48, /* ICMP checksum */
  0x02,0x00, /* Identifier */
  0x3a,0x00, /* sequence number */ 
  0x61,0x62,0x63,0x64,0x65,0x66,0x67,
  0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,
  0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,
  0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,
  0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,
  0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,
  0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,
  0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,
  0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,
  0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,
  0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,
  0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,
  0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,
  0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,
  0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,
  0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,
  0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,
  0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
  0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,
  0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,
  0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,
  0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
  0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
  0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
  0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,
  0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,
  0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,
  0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,
  0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,
  0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,
  0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,
  0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,
  0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,
  0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,
  0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,
  0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,
  0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,
  0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,
  0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,
  0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,
  0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
  0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,
  0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,
  0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,
  0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
  0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
  0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
  0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,
  0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,
  0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,
  0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,
  0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,
  0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,
  0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,
  0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,
  0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,
  0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,
  0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,
  0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,
  0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,
  0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,
  0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,
  0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,
  0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
  0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,
  0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,
  0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,
  0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
  0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
  0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
  0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,
  0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,
  0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,
  0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,
  0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,
  0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,
  0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,
  0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,
  0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,
  0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,
  0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,
  0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,
  0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,
  0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,
  0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,
  0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,
  0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
  0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,
  0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,
  0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,
  0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
  0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
  0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
  0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,
  0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,
  0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,
  0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,
  0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,
  0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77};
 
 
/* This should be 98 bytes big */
char ping_packet[] = {
  0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/
  //0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*DST MAC*/
  0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/
  0x08, 0x00, /*TYPE*/
  /* IP */
  0x45, /* Version, header length*/
  0x00, /* Differentiated services field */  
  0x00, 0x54, /* Total length */
  0x00, 0x00, /* Identification */
  0x40, /* Flags */
  0x00, /* Fragment offset */
  0x40, /* Time to live */
  0x01, /* Protocol (0x01 = ICMP */
  0xf0, 0x53, /* Header checksum */
  //0xc0, 0xa8, 0x64, 0xDE, /* Source IP */
  OUR_IP_BYTES, /* Source IP */
  DEST_IP_BYTES, /* Dest. IP */
  /* ICMP Message body */
  0x08, 0x00, 0x9a, 0xd4, 0xc8, 0x18, 0x00, 0x01, 0xd9, 0x8c, 0x54, 
  0x4a, 0x7b, 0x37, 0x01, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 
  0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
  0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 
  0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 
  0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
};
 
void send_test_packet()
{
 
  /*Send packet */
  //tx_packet((void*) ping_packet, 102);
  tx_packet((void*) broadcast_ping_packet, 102);
 
}
 
 
/* The interrupt handler.
*/
void
oeth_interrupt(void)
{
 
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  uint	int_events;
  int serviced;
 
  serviced = 0;
 
  /* Get the interrupt events that caused us to be here.
  */
  int_events = regs->int_src;
  regs->int_src = int_events;
 
 
  /* Indicate busy */
  if (int_events & OETH_INT_BUSY)
    {
      printf("\tBusy flag\n");
      /*
      printf("\n=tx_ | %x | %x | %x | %x | %x | %x | %x | %x\n",
      ((oeth_bd *)(OETH_BD_BASE))->len_status,
      ((oeth_bd *)(OETH_BD_BASE+8))->len_status,
      ((oeth_bd *)(OETH_BD_BASE+16))->len_status,
      ((oeth_bd *)(OETH_BD_BASE+24))->len_status,
      ((oeth_bd *)(OETH_BD_BASE+32))->len_status,
      ((oeth_bd *)(OETH_BD_BASE+40))->len_status,
      ((oeth_bd *)(OETH_BD_BASE+48))->len_status,
      ((oeth_bd *)(OETH_BD_BASE+56))->len_status);
      */	
      printf("=rx_ | %x | %x | %x | %x | %x | %x | %x | %x\n",
	     ((oeth_bd *)(OETH_BD_BASE+64))->len_status,
	     ((oeth_bd *)(OETH_BD_BASE+64+8))->len_status,
	     ((oeth_bd *)(OETH_BD_BASE+64+16))->len_status,
	     ((oeth_bd *)(OETH_BD_BASE+64+24))->len_status,
	     ((oeth_bd *)(OETH_BD_BASE+64+32))->len_status,
	     ((oeth_bd *)(OETH_BD_BASE+64+40))->len_status,
	     ((oeth_bd *)(OETH_BD_BASE+64+48))->len_status,
	     ((oeth_bd *)(OETH_BD_BASE+64+56))->len_status);
 
      printf("=int | txb %d | txe %d | rxb %d | rxe %d | busy %d\n",
	     (int_events & OETH_INT_TXB) > 0,
	     (int_events & OETH_INT_TXE) > 0,
	     (int_events & OETH_INT_RXF) > 0,
	     (int_events & OETH_INT_RXE) > 0,
	     (int_events & OETH_INT_BUSY) > 0);
    }
 
  /* Handle receive event in its own function.
  */
  if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) {
    serviced |= 0x1; 
    oeth_rx();
  }
 
  /* Handle transmit event in its own function.
  */
  if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
    serviced |= 0x2;
    oeth_tx();
    serviced |= 0x2;
 
  }
 
  return;
}
 
// ARP stuff
 
typedef unsigned long		IPaddr_t;
 
/*
*	Ethernet header
*/
typedef struct {
  unsigned char		et_dest[6];	/* Destination node		*/
  unsigned char		et_src[6];	/* Source node			*/
  unsigned short		et_protlen;	/* Protocol or length	*/
  unsigned char		et_dsap;	/* 802 DSAP			*/
  unsigned char		et_ssap;	/* 802 SSAP			*/
  unsigned char		et_ctl;		/* 802 control			*/
  unsigned char		et_snap1;	/* SNAP				*/
  unsigned char		et_snap2;
  unsigned char		et_snap3;
  unsigned short		et_prot;	/* 802 protocol		*/
} Ethernet_t;
 
#define ETHER_HDR_SIZE	14		/* Ethernet header size		*/
#define E802_HDR_SIZE	22		/* 802 ethernet header size	*/
#define PROT_IP		0x0800		/* IP protocol			*/
#define PROT_ARP	0x0806		/* IP ARP protocol		*/
#define PROT_RARP	0x8035		/* IP ARP protocol		*/
 
 
/*
 *	Internet Protocol (IP) header.
 */
typedef struct {
	unsigned char		ip_hl_v;        /* header length and version*/
	unsigned char		ip_tos;		/* type of service	    */
	unsigned short		ip_len;		/* total length		    */
	unsigned short		ip_id;		/* identification	    */
	unsigned short		ip_off;		/* fragment offset field    */
	unsigned char		ip_ttl;		/* time to live		    */
	unsigned char		ip_p;		/* protocol		    */
	unsigned short		ip_sum;		/* checksum		    */
	IPaddr_t	ip_src;		/* Source IP address		*/
	IPaddr_t	ip_dst;		/* Destination IP address	*/
	unsigned short		udp_src;	/* UDP source port	*/
	unsigned short		udp_dst;	/* UDP destination port	*/
	unsigned short		udp_len;	/* Length of UDP packet	*/
	unsigned short		udp_xsum;	/* Checksum		*/
} IP_t;
 
#define IP_HDR_SIZE_NO_UDP	(sizeof (IP_t) - 8)
#define IP_HDR_SIZE		(sizeof (IP_t))
 
#define IPPROTO_ICMP	 1	/* Internet Control Message Protocol	*/
#define IPPROTO_UDP	17	/* User Datagram Protocol		*/
 
 
/*
 * ICMP stuff (just enough to handle (host) redirect messages)
 */
#define ICMP_REDIRECT		5	/* Redirect (change route)	*/
 
/* Codes for REDIRECT. */
#define ICMP_REDIR_NET		0	/* Redirect Net			*/
#define ICMP_REDIR_HOST		1	/* Redirect Host		*/
 
#define ICMP_TYPE_ECHO_REPLY          0x00
#define ICMP_TYPE_ECHO_REQ          0x08
 
unsigned char ip_reply_packet[0x600] __attribute__ ((aligned (4))); // Save space for a full ICMP reply packet
 
typedef struct {
	unsigned char		type;
	unsigned char		code;
	unsigned short		checksum;
	union {
		struct {
			unsigned short	id;
			unsigned short	sequence;
		} echo;
		unsigned long	gateway;
		struct {
			unsigned short	__unused;
			unsigned short	mtu;
		} frag;
	} un;
} ICMP_t;
 
// From http://lkml.indiana.edu/hypermail/linux/kernel/9612.3/0060.html
unsigned short calculate_checksum(char* dats, unsigned int len) 
{
  unsigned int itr;
  unsigned long accum = 0;
  unsigned long longsum;
 
  // Sum all pairs of data
  for(itr=0;itr<(len & ~0x1);itr+=2)
    accum += (unsigned long)(((dats[itr]<<8)&0xff00)|(dats[itr+1]&0x00ff));
 
  if (len & 0x1) // Do leftover
    accum += (unsigned long) ((dats[itr-1]<<8)&0xff00);
 
  longsum = (unsigned long) (accum & 0xffff); 
  longsum += (unsigned long) (accum >> 16); // Sum the carries
  longsum += (longsum >> 16);
  return (unsigned short)((longsum ^ 0xffff) & 0xffff);
 
}
 
void
packet_check_icmp_header(void * pkt)
{
  Ethernet_t * eth_pkt;
  IP_t * ip;
  ICMP_t * icmp;
 
  unsigned int zero = 0;
 
  eth_pkt = (Ethernet_t *) pkt;
 
  // Check it's for our MAC
  char* eth_pkt_dst_mac = (char*) eth_pkt;
  if (!(
	((eth_pkt_dst_mac[0] == (char) ETH_MACADDR0) &&  // Either our MAC
	 (eth_pkt_dst_mac[1] == (char) ETH_MACADDR1) &&
	 (eth_pkt_dst_mac[2] == (char) ETH_MACADDR2) &&
	 (eth_pkt_dst_mac[3] == (char) ETH_MACADDR3) &&
	 (eth_pkt_dst_mac[4] == (char) ETH_MACADDR4) &&
	 (eth_pkt_dst_mac[5] == (char) ETH_MACADDR5)) || 
	((eth_pkt_dst_mac[0] == (char) 0xff) &&          // or broadcast MAC
	 (eth_pkt_dst_mac[1] == (char) 0xff) &&
	 (eth_pkt_dst_mac[2] == (char) 0xff) &&
	 (eth_pkt_dst_mac[3] == (char) 0xff) &&
	 (eth_pkt_dst_mac[4] == (char) 0xff) &&
	 (eth_pkt_dst_mac[5] == (char) 0xff)) 
	)
      )
 
    return ;
 
  // Check it's an IP packet
  if (!(eth_pkt->et_protlen == PROT_IP))
    return ; 
 
  pkt += ETHER_HDR_SIZE; // Skip eth header stuff
 
  ip = (IP_t*) pkt;
 
  // Check if this is an ICMP packet
  if (!(ip->ip_p == IPPROTO_ICMP))
    return ;
 
  // Check if this is for our IP, get pointer to the DST IP part of IP header
  // which is end of IP section - 4 bytes
  char * internet_protocol_adr = ((unsigned char*)ip + (IP_HDR_SIZE_NO_UDP-4));
 
  if (!((internet_protocol_adr[0] == our_ip[0]) &&
	(internet_protocol_adr[1] == our_ip[1]) &&
	(internet_protocol_adr[2] == our_ip[2]) &&
	(internet_protocol_adr[3] == our_ip[3])))
    return ;
 
  pkt += IP_HDR_SIZE_NO_UDP;
 
  icmp = (ICMP_t*) pkt;
 
  // Currently we only support replying to echo (ping) requests
 
  // Check for ICMP echo request type
  if (!(icmp->type == ICMP_TYPE_ECHO_REQ))
    return;
 
  // Go ahead and construct a response packet
  // Setup pointers
  Ethernet_t * reply_pkt  = (Ethernet_t *) &ip_reply_packet[0];
  IP_t       * reply_IP   = (IP_t*)        &ip_reply_packet[ETHER_HDR_SIZE];
  ICMP_t     * reply_ICMP = (ICMP_t*)      &ip_reply_packet[ETHER_HDR_SIZE+
							    IP_HDR_SIZE_NO_UDP];
  // Setup Ethernet header
  // Copy source MAC to destination MAC
  memcpy( (void*)&reply_pkt->et_dest , (void*)&eth_pkt->et_src , 6);
  reply_pkt->et_src[0] = ETH_MACADDR0;
  reply_pkt->et_src[1] = ETH_MACADDR1;
  reply_pkt->et_src[2] = ETH_MACADDR2;
  reply_pkt->et_src[3] = ETH_MACADDR3;
  reply_pkt->et_src[4] = ETH_MACADDR4;
  reply_pkt->et_src[5] = ETH_MACADDR5;
  reply_pkt->et_protlen = PROT_IP;
 
  // IP header
  reply_IP->ip_hl_v = 0x45; // version 4, 20 byte long header, not 100% on this!
  reply_IP->ip_tos = 0x00 ; // ToS (DSCP) - usually used for QoS, set to 0 
  unsigned short ip_indicated_length;
  // First copy total length indicated in received IP header to a variable, we
  // need it again later...
  memcpy ((void*)&ip_indicated_length, (void*)&ip->ip_len, 2);
  // Now copy into reply IP packet
  memcpy ((void*)&reply_IP->ip_len, (void*)&ip_indicated_length, 2);
  memcpy ((void*)&reply_IP->ip_id, (void*)&ip->ip_id, 2); // Copy ID
  reply_IP->ip_ttl = 0x40; // Packet TTL - 64, typical value
  reply_IP->ip_p = IPPROTO_ICMP; // Duh, this is an ICMP echo reply
  // Clear header checksum for now  
 
  memcpy ((void*)&reply_IP->ip_sum, (void*)&zero, 2);
  memcpy ((void*)&reply_IP->ip_src, (void*)&our_ip[0], 4); // Copy in our IP
  // "...return to sender... budupbadah address ....KNOWN ..."
  // WTF this memcpy() fails with alignment error...(?!?!)
  //memcpy (&reply_IP->ip_dst, &ip->ip_src, sizeof(IPaddr_t));
  //...OK then, do it manually.....
  unsigned char *ptr1, *ptr2;
  ptr1 = &reply_IP->ip_dst; ptr2 = &ip->ip_src;
  ptr1[0] = ptr2[0];
  ptr1[1] = ptr2[1];
  ptr1[2] = ptr2[2];
  ptr1[3] = ptr2[3];
 
  // Now calculate the CRC, probably move this to a fuction....
  unsigned short ip_sum = 0; // Initialise checksum value to 0
  int itr;   
  char* sum_data_ptr = (char*)reply_IP;
  ip_sum = calculate_checksum(sum_data_ptr,IP_HDR_SIZE_NO_UDP);
  /*
  for(itr=0;itr<IP_HDR_SIZE_NO_UDP;itr+=2)
    ip_sum += (((sum_data_ptr[itr]<<8)&0xff00)|(sum_data_ptr[itr+1]&0x00ff));
  while (ip_sum>>16)
    ip_sum = (ip_sum & 0xffff) + (ip_sum>>16);
  ip_sum = ~ip_sum;
  */
 
  memcpy ((void*)&reply_IP->ip_sum, (void*)&ip_sum, 2);
 
  //
  // Now construct ICMP part of packet
  //
  reply_ICMP->type = ICMP_TYPE_ECHO_REPLY; // ping response type
  reply_ICMP->code = icmp->code; // ICMP code same as sender (is this right?)
 
  // Clear ICMP checksum for now  
  memcpy ((void*)&reply_ICMP->checksum, (void*)&zero, 2);
 
  //
  // Simply copy in the data from the received packet
  // Figure out how much there is after the checksum
  // It should be :
  // length_from_received_IP_header - IP_header_length - initial_ICMP_packet_dat
  // 
  unsigned long icmp_data_length = ip_indicated_length - IP_HDR_SIZE_NO_UDP - 4;
  memcpy ((void*)&reply_ICMP->un,(void*)&icmp->un, icmp_data_length);
 
  // Now calculate checksum for ICMP data
  unsigned short icmp_sum = 0;
  sum_data_ptr = (char*)reply_ICMP;
  icmp_sum = calculate_checksum(sum_data_ptr,icmp_data_length+4);
 
  memcpy ((void*)&reply_ICMP->checksum, (void*)&icmp_sum, 2);
 
  // All done!
 
  tx_packet((void*)ip_reply_packet,ETHER_HDR_SIZE+ip_indicated_length);
 
}
 
 
 
/*
*	Address Resolution Protocol (ARP) header.
*/
typedef struct
{
  unsigned short		ar_hrd;	/* Format of hardware address	*/
#   define ARP_ETHER	    1		/* Ethernet  hardware address	*/
  unsigned short		ar_pro;	/* Format of protocol address	*/
  unsigned char		ar_hln;		/* Length of hardware address	*/
  unsigned char		ar_pln;		/* Length of protocol address	*/
  unsigned short		ar_op;	/* Operation			*/
#   define ARPOP_REQUEST    1		/* Request  to resolve  address	*/
#   define ARPOP_REPLY	    2		/* Response to previous request	*/
 
#   define RARPOP_REQUEST   3		/* Request  to resolve  address	*/
#   define RARPOP_REPLY	    4		/* Response to previous request */
 
  /*
  * The remaining fields are variable in size, according to
  * the sizes above, and are defined as appropriate for
  * specific hardware/protocol combinations.
  */
  unsigned char		ar_data[0];
#if 0
  unsigned char		ar_sha[];	/* Sender hardware address	*/
  unsigned char		ar_spa[];	/* Sender protocol address	*/
  unsigned char		ar_tha[];	/* Target hardware address	*/
  unsigned char		ar_tpa[];	/* Target protocol address	*/
#endif /* 0 */
} ARP_t;
 
#define ARP_HDR_SIZE	(8+20)		/* Size assuming ethernet	*/
 
char arp_reply_packet[(ETHER_HDR_SIZE + ARP_HDR_SIZE)];
 
void
packet_check_arp_header(void * pkt)
{
  Ethernet_t * eth_pkt;
 
  ARP_t * arp;
 
  //printf("packet_check_arp_header: pkt data at 0x%.8x\n",(unsigned long) pkt);
  eth_pkt = (Ethernet_t *) pkt;
 
  if (eth_pkt->et_protlen == 0x0806)
    {
      // Is an ARP request
      // Check the IP
      pkt += ETHER_HDR_SIZE; // Skip eth header stuff
      //printf("Is ARP protocol\npkt header now at 0x%.8x\n",pkt);
 
      arp = (ARP_t*) pkt;
 
      if (arp->ar_hrd == ARP_ETHER && arp->ar_op == ARPOP_REQUEST)
	{
	  // Skip forward to the target I.P address
 
	  char * internet_protocol_adr = (((unsigned long)&arp->ar_data[0]) + (arp->ar_hln * 2) + (arp->ar_pln));
 
	  //printf("Is ARP ethernet request\ncheck adr at 0x%.8x\n",internet_protocol_adr);
	  if ((internet_protocol_adr[0] == our_ip[0]) &&
	      (internet_protocol_adr[1] == our_ip[1]) &&
	      (internet_protocol_adr[2] == our_ip[2]) &&
	      (internet_protocol_adr[3] == our_ip[3]))
	    {
	      //printf("Got valid ARP request\n");
	      // Send ARP reply
 
	      Ethernet_t * reply_pkt = (Ethernet_t *)&arp_reply_packet[0];
	      ARP_t * reply_arp = (ARP_t*)&arp_reply_packet[ETHER_HDR_SIZE];
	      memcpy( (void*)&reply_pkt->et_dest , (void*)&eth_pkt->et_src , 6);
	      reply_pkt->et_src[0] = ETH_MACADDR0;
	      reply_pkt->et_src[1] = ETH_MACADDR1;
	      reply_pkt->et_src[2] = ETH_MACADDR2;
	      reply_pkt->et_src[3] = ETH_MACADDR3;
	      reply_pkt->et_src[4] = ETH_MACADDR4;
	      reply_pkt->et_src[5] = ETH_MACADDR5;
	      reply_pkt->et_protlen = 0x0806;
	      // ARP part of packet	      
	      reply_arp->ar_hrd = ARP_ETHER;
	      reply_arp->ar_pro = 0x0800; // IP Protocol
	      reply_arp->ar_hln = 0x06;
	      reply_arp->ar_pln = 0x04;
	      reply_arp->ar_op = ARPOP_REPLY;
	      // My MAC
	      memcpy( (void*)&reply_arp->ar_data[0] , (void*)&reply_pkt->et_src , 6);
	      // My IP
	      memcpy( (void*)&reply_arp->ar_data[6] , (void*)&our_ip , 4);
	      // Their MAC
	      memcpy( (void*)&reply_arp->ar_data[10] , (void*)&eth_pkt->et_src , 6);
	      // Their IP
	      char * their_internet_protocol_adr = 
		(((unsigned long)&arp->ar_data[0]) + arp->ar_hln );
	      memcpy( (void*)&reply_arp->ar_data[16] , (void*)&their_internet_protocol_adr[0] , 4);
 
	      tx_packet((void*)arp_reply_packet,(ETHER_HDR_SIZE+ARP_HDR_SIZE) );
 
	    }
	}
    }
}
 
 
 
static void
oeth_rx(void)
{
  volatile oeth_regs *regs;
  regs = (oeth_regs *)(OETH_REG_BASE);
 
  volatile oeth_bd *rx_bdp;
  int	pkt_len, i;
  int	bad = 0;
 
  rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
 
  if (print_packet_contents)
    printf("rx");
 
  /* Find RX buffers marked as having received data */
  for(i = 0; i < OETH_RXBD_NUM; i++)
    {
      if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */
	/* Check status for errors.
	*/
	if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
	  bad = 1;
	}
	if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) {
	  bad = 1;
	}
	if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) {
	  bad = 1;
	}
	if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) {
	  bad = 1;
	}
	if (rx_bdp[i].len_status & OETH_RX_BD_MISS) {
 
	}
	if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) {
	  bad = 1;
	}
 
	if (bad) {
	  printf("RXE: 0x%x\n",rx_bdp[i].len_status & OETH_RX_BD_STATS);
	  rx_bdp[i].len_status &= ~OETH_RX_BD_STATS;
	  rx_bdp[i].len_status |= OETH_RX_BD_EMPTY;
	  bad = 0;
	  continue;
	}
	else {
 
	  /* Process the incoming frame.
	  */
	  pkt_len = rx_bdp[i].len_status >> 16;
 
	  /* Do something here with the data - copy it into userspace, perhaps. */
	  // See if it's an ARP packet
	  packet_check_arp_header((void *)rx_bdp[i].addr );
	  // See if it's an ICMP echo request
	  packet_check_icmp_header((void *)rx_bdp[i].addr );
	  if (print_packet_contents)
	    {
	      oeth_print_packet(rx_bdp[i].addr, rx_bdp[i].len_status >> 16);
	      printf("\t end of packet\n\n");
	    }
	  /* finish up */
	  rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */
	  rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */
 
 
	}
      }
    }
}
 
 
 
static void
oeth_tx(void)
{
  volatile oeth_bd *tx_bd;
  int i;
  if (print_packet_contents)
    printf("tx");
 
  tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/
 
  /* Go through the TX buffs, search for one that was just sent */
  for(i = 0; i < OETH_TXBD_NUM; i++)
    {
      /* Looking for buffer NOT ready for transmit. and IRQ enabled */
      if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) )
	{
	  //oeth_print_packet(tx_bd[i].addr, (tx_bd[i].len_status >> 16));
	  /* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */
	  tx_bd[i].len_status &= ~OETH_TX_BD_IRQ;
 
	  /* Probably good to check for TX errors here */
	  // Check if either carrier sense lost or colission indicated
	  if (tx_bd[i].len_status & OETH_TX_BD_STATS)
	    printf("TXER: 0x%x\n",(tx_bd[i].len_status & OETH_TX_BD_STATS));
 
	  if (print_packet_contents)
	    printf("T%d",i);
	}
    }
  return;  
}
 
 
int main ()
{
 
  print_packet_contents = 0; // Default to not printing packet contents.
 
  /* Initialise vector handler */
  int_init();
 
  /* Install ethernet interrupt handler, it is enabled here too */
  int_add(ETH0_IRQ, oeth_interrupt, 0);
 
  /* Enable interrupts */
  cpu_enable_user_interrupts();
 
  last_char=0; /* Variable init for spin_cursor() */
  next_tx_buf_num = 4; /* init for tx buffer counter */
 
  uart_init(DEFAULT_UART); // init the UART before we can printf
  printf("\n\teth ping program\n\n");
  printf("\n\tboard IP: %d.%d.%d.%d\n",our_ip[0]&0xff,our_ip[1]&0xff,
	 our_ip[2]&0xff,our_ip[3]&0xff);
 
  ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */
 
  //scan_ethphys(); /* Scan MIIM bus for PHYs */
  //ethphy_init(); /* Attempt reset and configuration of PHY via MIIM */
  //ethmac_scanstatus(); /* Enable scanning of status register via MIIM */
 
  /* Loop, monitoring user input from TTY */
  while(1)  
    {
      char c;
 
      while(!uart_check_for_char(DEFAULT_UART))
	{
	  spin_cursor();
	  //oeth_monitor_rx();
	}
 
      c = uart_getc(DEFAULT_UART);
 
      if (c == 's')
	tx_packet((void*) ping_packet, 98);
      else if (c == 'S')
	tx_packet((void*)big_ping_packet, 1514);
      else if (c == 'h')
	scan_ethphys();
      else if (c == 'i')
	ethphy_init();
      else if (c == 'P')
	{
	  print_packet_contents = print_packet_contents ? 0 : 1;
	  if (print_packet_contents)
	    printf("Enabling packet dumping\n");
	  else
	    printf("Packet dumping disabled\n");
	}
      else if (c == 'p')
	oeth_printregs();
      else if (c == '0')
	scan_ethphy(0);
      else if (c == '1')
	scan_ethphy(1);
      else if (c == '7')
	{
	  //scan_ethphy(7);
	  //ethphy_print_status(7);
	  printf("ext_sr 0x%x\n",eth_mii_read(0x7, 0x1b));
	}
      else if (c == 'r')
	{
	  ethphy_reset(7);
	  printf("PHY reset\n");
	}
      else if (c == 'R')
	{
	  //oeth_reset_tx_bd_pointer();
	  ethmac_setup();
	  printf("MAC reset\n");
	}
      else if (c == 'n')
	ethphy_reneg(7);
      else if (c == 'N')
	ethphy_set_autoneg(7);
      else if (c == 'm')
	ethmac_togglehugen();
      else if (c == 't')
	ethphy_set_10mbit(0);
      else if (c == 'w')
	{
	  // Play with HWCFG mode of Alaska 88e1111 Phy
	  c = uart_getc(DEFAULT_UART);
	  short newvalue;
	  // c is an ascii char, let's convert it to actual hex value
	  if (c >= 'A' && c <= 'F')
	    newvalue = c - (65 - 10);
	  else if (c >= 'a' && c <= 'f')
	    newvalue  = c - (99 - 10);
	  else if (c >= '0' && c <= '9')
	    newvalue  = c - 48;
 
	  // Take this value and or it into the bottom bit (supposedly ext_sr)
#define MII_M1111_PHY_EXT_SR		0x1b
	  short ext_sr;
	  ext_sr = eth_mii_read(0x7, MII_M1111_PHY_EXT_SR);
#define MII_M1111_HWCFG_MODE_MASK		0xf	  
	  ext_sr &= ~MII_M1111_HWCFG_MODE_MASK;
	  ext_sr |= (short) newvalue;
	  eth_mii_write(0x7, MII_M1111_PHY_EXT_SR, ext_sr);
	  printf("ext_sr updated to - 0x%x\n",eth_mii_read(0x7, MII_M1111_PHY_EXT_SR));
	}
      else if ( c == 'b' )
	{
	  printf("\n\t---\n");
	  oeth_dump_bds();
	  printf("\t---\n");
	}
 
      else if ( c == 'B' )
	{
	  tx_packet((void*) broadcast_ping_packet, 298);
	}
 
    }
 
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.