//  [c]
error_t enc624j600Init(NetInterface *interface)
{
   uint16_t temp;
   Enc624j600Context *context;

   //Debug message
   TRACE_INFO("Initializing ENC624J600 Ethernet controller...\r\n");

   //Initialize SPI
   interface->spiDriver->init();
   //Initialize external interrupt line
   interface->extIntDriver->init();

   //Point to the driver context
   context = (Enc624j600Context *) interface->nicContext;

   //Initialize driver specific variables
   context->nextPacket = ENC624J600_RX_BUFFER_START;

   //Allocate RX buffer
   context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
   //Failed to allocate memory?
   if(context->rxBuffer == NULL)
   {
      return ERROR_OUT_OF_MEMORY;
   }

   //Issue a system reset
   enc624j600SoftReset(interface);

   //Disable CLKOUT output
   enc624j600WriteReg(interface, ENC624J600_REG_ECON2, ECON2_ETHEN | ECON2_STRCH);

   //Optionally set the station MAC address
   if(macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
   {
      //Use the factory preprogrammed station address
      temp = enc624j600ReadReg(interface, ENC624J600_REG_MAADR1);
      interface->macAddr.w[0] = letoh16(temp);
      temp = enc624j600ReadReg(interface, ENC624J600_REG_MAADR2);
      interface->macAddr.w[1] = letoh16(temp);
      temp = enc624j600ReadReg(interface, ENC624J600_REG_MAADR3);
      interface->macAddr.w[2] = letoh16(temp);

      //Generate the 64-bit interface identifier
      macAddrToEui64(&interface->macAddr, &interface->eui64);
   }
   else
   {
      //Override the factory preprogrammed address
      temp = htole16(interface->macAddr.w[0]);
      enc624j600WriteReg(interface, ENC624J600_REG_MAADR1, temp);
      temp = htole16(interface->macAddr.w[1]);
      enc624j600WriteReg(interface, ENC624J600_REG_MAADR2, temp);
      temp = htole16(interface->macAddr.w[2]);
      enc624j600WriteReg(interface, ENC624J600_REG_MAADR3, temp);
   }

   //Set receive buffer location
   enc624j600WriteReg(interface, ENC624J600_REG_ERXST, ENC624J600_RX_BUFFER_START);
   //Program the tail pointer ERXTAIL to the last even address of the buffer
   enc624j600WriteReg(interface, ENC624J600_REG_ERXTAIL, ENC624J600_RX_BUFFER_STOP);

   //Configure the receive filters
   enc624j600WriteReg(interface, ENC624J600_REG_ERXFCON, ERXFCON_HTEN |
      ERXFCON_CRCEN | ERXFCON_RUNTEN | ERXFCON_UCEN | ERXFCON_BCEN);

   //Initialize the hash table
   enc624j600WriteReg(interface, ENC624J600_REG_EHT1, 0x0000);
   enc624j600WriteReg(interface, ENC624J600_REG_EHT2, 0x0000);
   enc624j600WriteReg(interface, ENC624J600_REG_EHT3, 0x0000);
   enc624j600WriteReg(interface, ENC624J600_REG_EHT4, 0x0000);

   //All short frames will be zero-padded to 60 bytes and a valid CRC is then appended
   enc624j600WriteReg(interface, ENC624J600_REG_MACON2,
      MACON2_DEFER | MACON2_PADCFG0 | MACON2_TXCRCEN | MACON2_R1);

   //Program the MAMXFL register with the maximum frame length to be accepted
   enc624j600WriteReg(interface, ENC624J600_REG_MAMXFL, ETH_MAX_FRAME_SIZE);

   //PHY initialization
   enc624j600WritePhyReg(interface, ENC624J600_PHY_REG_PHANA, PHANA_ADPAUS0 |
      PHANA_AD100FD | PHANA_AD100 | PHANA_AD10FD | PHANA_AD10 | PHANA_ADIEEE0);

   //Clear interrupt flags
   enc624j600WriteReg(interface, ENC624J600_REG_EIR, 0x0000);

   //Configure interrupts as desired
   enc624j600WriteReg(interface, ENC624J600_REG_EIE, EIE_INTIE |
      EIE_LINKIE | EIE_PKTIE | EIE_TXIE | EIE_TXABTIE);

   //Set RXEN to enable reception
   enc624j600SetBit(interface, ENC624J600_REG_ECON1, ECON1_RXEN);

   //Dump registers for debugging purpose
   enc624j600DumpReg(interface);
   enc624j600DumpPhyReg(interface);

   //Accept any packets from the upper layer
   osSetEvent(&interface->nicTxEvent);

   //Force the TCP/IP stack to poll the link state at startup
   interface->nicEvent = TRUE;
   //Notify the TCP/IP stack of the event
   osSetEvent(&netEvent);

   //Successful initialization
   return NO_ERROR;
}