//  [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_ECON2, ENC624J600_ECON2_ETHEN |
      ENC624J600_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_MAADR1);
      interface->macAddr.w[0] = letoh16(temp);
      temp = enc624j600ReadReg(interface, ENC624J600_MAADR2);
      interface->macAddr.w[1] = letoh16(temp);
      temp = enc624j600ReadReg(interface, ENC624J600_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_MAADR1, temp);
      temp = htole16(interface->macAddr.w[1]);
      enc624j600WriteReg(interface, ENC624J600_MAADR2, temp);
      temp = htole16(interface->macAddr.w[2]);
      enc624j600WriteReg(interface, ENC624J600_MAADR3, temp);
   }

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

   //Configure the receive filters
   enc624j600WriteReg(interface, ENC624J600_ERXFCON, ENC624J600_ERXFCON_HTEN |
      ENC624J600_ERXFCON_CRCEN | ENC624J600_ERXFCON_RUNTEN |
      ENC624J600_ERXFCON_UCEN | ENC624J600_ERXFCON_BCEN);

   //Initialize the hash table
   enc624j600WriteReg(interface, ENC624J600_EHT1, 0x0000);
   enc624j600WriteReg(interface, ENC624J600_EHT2, 0x0000);
   enc624j600WriteReg(interface, ENC624J600_EHT3, 0x0000);
   enc624j600WriteReg(interface, ENC624J600_EHT4, 0x0000);

   //All short frames will be zero-padded to 60 bytes and a valid CRC is then
   //appended
   enc624j600WriteReg(interface, ENC624J600_MACON2, ENC624J600_MACON2_DEFER |
      ENC624J600_MACON2_PADCFG_AUTO | ENC624J600_MACON2_TXCRCEN |
      ENC624J600_MACON2_R1_DEFAULT);

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

   //PHY initialization
   enc624j600WritePhyReg(interface, ENC624J600_PHANA, ENC624J600_PHANA_ADPAUS0 |
      ENC624J600_PHANA_AD100FD | ENC624J600_PHANA_AD100 | ENC624J600_PHANA_AD10FD |
      ENC624J600_PHANA_AD10 | ENC624J600_PHANA_ADIEEE_DEFAULT);

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

   //Configure interrupts as desired
   enc624j600WriteReg(interface, ENC624J600_EIE, ENC624J600_EIE_INTIE |
      ENC624J600_EIE_LINKIE | ENC624J600_EIE_PKTIE | ENC624J600_EIE_TXIE |
      ENC624J600_EIE_TXABTIE);

   //Set RXEN to enable reception
   enc624j600SetBit(interface, ENC624J600_ECON1, ENC624J600_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;
}