//  [c]
error_t dm9000Init(NetInterface *interface)
{
   uint_t i;
   uint16_t vendorId;
   uint16_t productId;
   uint8_t chipRev;
   Dm9000Context *context;

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

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

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

   //Initialize driver specific variables
   context->queuedPackets = 0;

   //Allocate TX and RX buffers
   context->txBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);
   context->rxBuffer = memPoolAlloc(ETH_MAX_FRAME_SIZE);

   //Failed to allocate memory?
   if(context->txBuffer == NULL || context->rxBuffer == NULL)
   {
      //Clean up side effects
      memPoolFree(context->txBuffer);
      memPoolFree(context->rxBuffer);

      //Report an error
      return ERROR_OUT_OF_MEMORY;
   }

   //Retrieve vendorID, product ID and chip revision
   vendorId = (dm9000ReadReg(DM9000_VIDH) << 8) | dm9000ReadReg(DM9000_VIDL);
   productId = (dm9000ReadReg(DM9000_PIDH) << 8) | dm9000ReadReg(DM9000_PIDL);
   chipRev = dm9000ReadReg(DM9000_CHIPR);

   //Check vendor ID and product ID
   if(vendorId != DM9000_VID || productId != DM9000_PID)
   {
      return ERROR_WRONG_IDENTIFIER;
   }

   //Check chip revision
   if(chipRev != DM9000_CHIPR_REV_A && chipRev != DM9000_CHIPR_REV_B)
   {
      return ERROR_WRONG_IDENTIFIER;
   }

   //Power up the internal PHY by clearing PHYPD
   dm9000WriteReg(DM9000_GPR, 0x00);
   //Wait for the PHY to be ready
   sleep(10);

   //Software reset
   dm9000WriteReg(DM9000_NCR, DM9000_NCR_RST);
   //Wait for the reset to complete
   while((dm9000ReadReg(DM9000_NCR) & DM9000_NCR_RST) != 0)
   {
   }

   //PHY software reset
   dm9000WritePhyReg(DM9000_BMCR, DM9000_BMCR_RST);
   //Wait for the PHY reset to complete
   while((dm9000ReadPhyReg(DM9000_BMCR) & DM9000_BMCR_RST) != 0)
   {
   }

   //Debug message
   TRACE_INFO("  VID = 0x%04" PRIX16 "\r\n", vendorId);
   TRACE_INFO("  PID = 0x%04" PRIX16 "\r\n", productId);
   TRACE_INFO("  CHIPR = 0x%02" PRIX8 "\r\n", chipRev);
   TRACE_INFO("  PHYIDR1 = 0x%04" PRIX16 "\r\n", dm9000ReadPhyReg(DM9000_PHYIDR1));
   TRACE_INFO("  PHYIDR2 = 0x%04" PRIX16 "\r\n", dm9000ReadPhyReg(DM9000_PHYIDR2));

   //Enable loopback mode?
#if (DM9000_LOOPBACK_MODE == ENABLED)
   //Enable loopback mode
   dm9000WriteReg(DM9000_NCR, DM9000_NCR_LBK_PHY);

   //Set operation mode
   dm9000WritePhyReg(DM9000_BMCR, DM9000_BMCR_LOOPBACK | DM9000_BMCR_SPEED_SEL |
      DM9000_BMCR_AN_EN | DM9000_BMCR_DUPLEX_MODE);
#endif

   //Set host MAC address
   for(i = 0; i < 6; i++)
   {
      dm9000WriteReg(DM9000_PAR0 + i, interface->macAddr.b[i]);
   }

   //Initialize hash table
   for(i = 0; i < 8; i++)
   {
      dm9000WriteReg(DM9000_MAR0 + i, 0x00);
   }

   //Always accept broadcast packets
   dm9000WriteReg(DM9000_MAR7, 0x80);

   //Enable the Pointer Auto Return function
   dm9000WriteReg(DM9000_IMR, DM9000_IMR_PAR);

   //Clear NSR status bits
   dm9000WriteReg(DM9000_NSR, DM9000_NSR_WAKEST | DM9000_NSR_TX2END |
      DM9000_NSR_TX1END);

   //Clear interrupt flags
   dm9000WriteReg(DM9000_ISR, DM9000_ISR_LNKCHG | DM9000_ISR_UDRUN |
      DM9000_ISR_ROO | DM9000_ISR_ROS | DM9000_ISR_PT | DM9000_ISR_PR);

   //Enable interrupts
   dm9000WriteReg(DM9000_IMR, DM9000_IMR_PAR | DM9000_IMR_LNKCHGI |
      DM9000_IMR_PTI | DM9000_IMR_PRI);

   //Enable the receiver by setting RXEN
   dm9000WriteReg(DM9000_RCR, DM9000_RCR_DIS_LONG | DM9000_RCR_DIS_CRC |
      DM9000_RCR_RXEN);

   //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;
}