void WritePhyRegister(ENC28J60PhyRegister registerAddress, UInt16 value)
        {
            lock (_spiLock)
            {
                // write the PHY register address to MIREGADR
                WriteControlRegister(ENC28J60Register.MIREGADR, (byte)registerAddress);
                // write the value to our MIWRL and MIWRH registers, in that order.
                WriteControlRegister(ENC28J60Register.MIWRL, ENC28J60Register.MIWRH, value);

                // wait for the PHY register value to be written successfully
                Int64 startTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks;
                bool miiOperationSuccess = false;
                byte mistat;
                do
                {
                    mistat = ReadControlRegister(ENC28J60Register.MISTAT, true);
                    if ((mistat & (byte)ENC28J60RegisterBits.MISTAT_BUSY) == 0x00)
                    {
                        miiOperationSuccess = true;
                        break;
                    }
                } while ((Utility.GetMachineTime().Ticks - startTicks) / System.TimeSpan.TicksPerMillisecond < 20); // wait up to 20ms

                if (!miiOperationSuccess)
                    throw new Exception(); /* TODO: this should be a "could not configure network interface" exception */
            }
        }
        UInt16 ReadPhyRegister(ENC28J60PhyRegister registerAddress)
        {
            lock (_spiLock)
            {
                // write the PHY register address to MIREGADR
                WriteControlRegister(ENC28J60Register.MIREGADR, (byte)registerAddress);
                // set the MICMD.MIIRD bit to retrieve the register value
                byte micmd = ReadControlRegister(ENC28J60Register.MICMD, true);
                micmd |= (byte)ENC28J60RegisterBits.MICMD_MIIRD;
                WriteControlRegister(ENC28J60Register.MICMD, micmd);

                // wait for the PHY register value to be read successfully
                Int64 startTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks;
                bool miiOperationSuccess = false;
                byte mistat;
                do
                {
                    mistat = ReadControlRegister(ENC28J60Register.MISTAT, true);
                    if ((mistat & (byte)ENC28J60RegisterBits.MISTAT_BUSY) == 0x00)
                    {
                        miiOperationSuccess = true;
                        break;
                    }
                } while ((Utility.GetMachineTime().Ticks - startTicks) / System.TimeSpan.TicksPerMillisecond < 20); // wait up to 20ms

                if (!miiOperationSuccess)
                    throw new Exception(); /* TODO: this should be a "could not configure network interface" exception */

                // retrieve our register value
                UInt16 returnValue = ReadControlRegister(ENC28J60Register.MIRDL, ENC28J60Register.MIRDH, true);

                // clear the MICMD.MIIRD bit
                micmd &= (byte)~ENC28J60RegisterBits.MICMD_MIIRD;
                WriteControlRegister(ENC28J60Register.MICMD, micmd);

                // return our register value
                return returnValue;
            }
        }