// // lan7800.c // // This driver has been written based on the Linux lan78xx driver which is: // Copyright (C) 2015 Microchip Technology // Driver author: WOOJUNG HUH // Licensed under GPLv2 // // USPi - An USB driver for Raspberry Pi written in C // Copyright (C) 2018 R. Stange // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include #include #include #include #include // Sizes #define HS_USB_PKT_SIZE 512 #define MAX_RX_FIFO_SIZE (12 * 1024) #define MAX_TX_FIFO_SIZE (12 * 1024) #define DEFAULT_BURST_CAP_SIZE MAX_TX_FIFO_SIZE #define DEFAULT_BULK_IN_DELAY 0x800 #define RX_HEADER_SIZE (4 + 4 + 2) #define TX_HEADER_SIZE (4 + 4) #define MAX_RX_FRAME_SIZE (2*6 + 2 + 1500 + 4) // USB vendor requests #define WRITE_REGISTER 0xA0 #define READ_REGISTER 0xA1 // Device registers #define ID_REV 0x000 #define ID_REV_CHIP_ID_MASK 0xFFFF0000 #define ID_REV_CHIP_ID_7800 0x7800 #define INT_STS 0x00C #define INT_STS_CLEAR_ALL 0xFFFFFFFF #define HW_CFG 0x010 #define HW_CFG_CLK125_EN 0x02000000 #define HW_CFG_REFCLK25_EN 0x01000000 #define HW_CFG_LED3_EN 0x00800000 #define HW_CFG_LED2_EN 0x00400000 #define HW_CFG_LED1_EN 0x00200000 #define HW_CFG_LED0_EN 0x00100000 #define HW_CFG_EEE_PHY_LUSU 0x00020000 #define HW_CFG_EEE_TSU 0x00010000 #define HW_CFG_NETDET_STS 0x00008000 #define HW_CFG_NETDET_EN 0x00004000 #define HW_CFG_EEM 0x00002000 #define HW_CFG_RST_PROTECT 0x00001000 #define HW_CFG_CONNECT_BUF 0x00000400 #define HW_CFG_CONNECT_EN 0x00000200 #define HW_CFG_CONNECT_POL 0x00000100 #define HW_CFG_SUSPEND_N_SEL_MASK 0x000000C0 #define HW_CFG_SUSPEND_N_SEL_2 0x00000000 #define HW_CFG_SUSPEND_N_SEL_12N 0x00000040 #define HW_CFG_SUSPEND_N_SEL_012N 0x00000080 #define HW_CFG_SUSPEND_N_SEL_0123N 0x000000C0 #define HW_CFG_SUSPEND_N_POL 0x00000020 #define HW_CFG_MEF 0x00000010 #define HW_CFG_ETC 0x00000008 #define HW_CFG_LRST 0x00000002 #define HW_CFG_SRST 0x00000001 #define PMT_CTL 0x014 #define PMT_CTL_EEE_WAKEUP_EN 0x00002000 #define PMT_CTL_EEE_WUPS 0x00001000 #define PMT_CTL_MAC_SRST 0x00000800 #define PMT_CTL_PHY_PWRUP 0x00000400 #define PMT_CTL_RES_CLR_WKP_MASK 0x00000300 #define PMT_CTL_RES_CLR_WKP_STS 0x00000200 #define PMT_CTL_RES_CLR_WKP_EN 0x00000100 #define PMT_CTL_READY 0x00000080 #define PMT_CTL_SUS_MODE_MASK 0x00000060 #define PMT_CTL_SUS_MODE_0 0x00000000 #define PMT_CTL_SUS_MODE_1 0x00000020 #define PMT_CTL_SUS_MODE_2 0x00000040 #define PMT_CTL_SUS_MODE_3 0x00000060 #define PMT_CTL_PHY_RST 0x00000010 #define PMT_CTL_WOL_EN 0x00000008 #define PMT_CTL_PHY_WAKE_EN 0x00000004 #define PMT_CTL_WUPS_MASK 0x00000003 #define PMT_CTL_WUPS_MLT 0x00000003 #define PMT_CTL_WUPS_MAC 0x00000002 #define PMT_CTL_WUPS_PHY 0x00000001 #define USB_CFG0 0x080 #define USB_CFG_BIR 0x00000040 #define USB_CFG_BCE 0x00000020 #define BURST_CAP 0x090 #define BURST_CAP_SIZE_MASK_ 0x000000FF #define BULK_IN_DLY 0x094 #define BULK_IN_DLY_MASK_ 0x0000FFFF #define INT_EP_CTL 0x098 #define INT_EP_INTEP_ON 0x80000000 #define INT_STS_EEE_TX_LPI_STRT_EN 0x04000000 #define INT_STS_EEE_TX_LPI_STOP_EN 0x02000000 #define INT_STS_EEE_RX_LPI_EN 0x01000000 #define INT_EP_RDFO_EN 0x00400000 #define INT_EP_TXE_EN 0x00200000 #define INT_EP_TX_DIS_EN 0x00080000 #define INT_EP_RX_DIS_EN 0x00040000 #define INT_EP_PHY_INT_EN 0x00020000 #define INT_EP_DP_INT_EN 0x00010000 #define INT_EP_MAC_ERR_EN 0x00008000 #define INT_EP_TDFU_EN 0x00004000 #define INT_EP_TDFO_EN 0x00002000 #define INT_EP_UTX_FP_EN 0x00001000 #define INT_EP_GPIO_EN_MASK 0x00000FFF #define RFE_CTL 0x0B0 #define RFE_CTL_IGMP_COE 0x00004000 #define RFE_CTL_ICMP_COE 0x00002000 #define RFE_CTL_TCPUDP_COE 0x00001000 #define RFE_CTL_IP_COE 0x00000800 #define RFE_CTL_BCAST_EN 0x00000400 #define RFE_CTL_MCAST_EN 0x00000200 #define RFE_CTL_UCAST_EN 0x00000100 #define RFE_CTL_VLAN_STRIP 0x00000080 #define RFE_CTL_DISCARD_UNTAGGED 0x00000040 #define RFE_CTL_VLAN_FILTER 0x00000020 #define RFE_CTL_SA_FILTER 0x00000010 #define RFE_CTL_MCAST_HASH 0x00000008 #define RFE_CTL_DA_HASH 0x00000004 #define RFE_CTL_DA_PERFECT 0x00000002 #define RFE_CTL_RST 0x00000001 #define FCT_RX_CTL 0x0C0 #define FCT_RX_CTL_EN 0x80000000 #define FCT_RX_CTL_RST 0x40000000 #define FCT_RX_CTL_SBF 0x02000000 #define FCT_RX_CTL_OVFL 0x01000000 #define FCT_RX_CTL_DROP 0x00800000 #define FCT_RX_CTL_NOT_EMPTY 0x00400000 #define FCT_RX_CTL_EMPTY 0x00200000 #define FCT_RX_CTL_DIS 0x00100000 #define FCT_RX_CTL_USED_MASK 0x0000FFFF #define FCT_TX_CTL 0x0C4 #define FCT_TX_CTL_EN 0x80000000 #define FCT_TX_CTL_RST 0x40000000 #define FCT_TX_CTL_NOT_EMPTY 0x00400000 #define FCT_TX_CTL_EMPTY 0x00200000 #define FCT_TX_CTL_DIS 0x00100000 #define FCT_TX_CTL_USED_MASK 0x0000FFFF #define FCT_RX_FIFO_END 0x0C8 #define FCT_RX_FIFO_END_MASK 0x0000007F #define FCT_TX_FIFO_END 0x0CC #define FCT_TX_FIFO_END_MASK 0x0000003F #define FCT_FLOW 0x0D0 #define MAC_CR 0x100 #define MAC_CR_GMII_EN 0x00080000 #define MAC_CR_EEE_TX_CLK_STOP_EN 0x00040000 #define MAC_CR_EEE_EN 0x00020000 #define MAC_CR_EEE_TLAR_EN 0x00010000 #define MAC_CR_ADP 0x00002000 #define MAC_CR_AUTO_DUPLEX 0x00001000 #define MAC_CR_AUTO_SPEED 0x00000800 #define MAC_CR_LOOPBACK 0x00000400 #define MAC_CR_BOLMT_MASK 0x000000C0 #define MAC_CR_FULL_DUPLEX 0x00000008 #define MAC_CR_SPEED_MASK 0x00000006 #define MAC_CR_SPEED_1000 0x00000004 #define MAC_CR_SPEED_100 0x00000002 #define MAC_CR_SPEED_10 0x00000000 #define MAC_CR_RST 0x00000001 #define MAC_RX 0x104 #define MAC_RX_MAX_SIZE_SHIFT 16 #define MAC_RX_MAX_SIZE_MASK 0x3FFF0000 #define MAC_RX_FCS_STRIP 0x00000010 #define MAC_RX_VLAN_FSE 0x00000004 #define MAC_RX_RXD 0x00000002 #define MAC_RX_RXEN 0x00000001 #define MAC_TX 0x108 #define MAC_TX_BAD_FCS 0x00000004 #define MAC_TX_TXD 0x00000002 #define MAC_TX_TXEN 0x00000001 #define FLOW 0x10C #define RX_ADDRH 0x118 #define RX_ADDRH_MASK_ 0x0000FFFF #define RX_ADDRL 0x11C #define RX_ADDRL_MASK_ 0xFFFFFFFF #define MII_ACC 0x120 #define MII_ACC_PHY_ADDR_SHIFT 11 #define MII_ACC_PHY_ADDR_MASK 0x0000F800 #define PHY_ADDRESS 1 #define MII_ACC_MIIRINDA_SHIFT 6 #define MII_ACC_MIIRINDA_MASK 0x000007C0 #define MII_ACC_MII_READ 0x00000000 #define MII_ACC_MII_WRITE 0x00000002 #define MII_ACC_MII_BUSY 0x00000001 #define MII_DATA 0x124 #define MII_DATA_MASK 0x0000FFFF #define MAF_BASE 0x400 #define MAF_HIX 0x00 #define MAF_LOX 0x04 #define NUM_OF_MAF 33 #define MAF_HI_BEGIN (MAF_BASE + MAF_HIX) #define MAF_LO_BEGIN (MAF_BASE + MAF_LOX) #define MAF_HI(index) (MAF_BASE + (8 * (index)) + (MAF_HIX)) #define MAF_LO(index) (MAF_BASE + (8 * (index)) + (MAF_LOX)) #define MAF_HI_VALID 0x80000000 #define MAF_HI_TYPE_MASK 0x40000000 #define MAF_HI_TYPE_SRC 0x40000000 #define MAF_HI_TYPE_DST 0x00000000 #define MAF_HI_ADDR_MASK 0x0000FFFF #define MAF_LO_ADDR_MASK 0xFFFFFFFF // TX command A #define TX_CMD_A_FCS 0x00400000 #define TX_CMD_A_LEN_MASK 0x000FFFFF // RX command A #define RX_CMD_A_RED 0x00400000 #define RX_CMD_A_LEN_MASK 0x00003FFF boolean LAN7800DeviceInitMACAddress (TLAN7800Device *pThis); boolean LAN7800DeviceInitPHY (TLAN7800Device *pThis); boolean LAN7800DevicePHYWrite (TLAN7800Device *pThis, u8 uchIndex, u16 usValue); boolean LAN7800DevicePHYRead (TLAN7800Device *pThis, u8 uchIndex, u16 *pValue); boolean LAN7800DeviceWaitReg (TLAN7800Device *pThis, u32 nIndex, u32 nMask, u32 nCompare); boolean LAN7800DeviceReadWriteReg (TLAN7800Device *pThis, u32 nIndex, u32 nOrMask, u32 nAndMask); boolean LAN7800DeviceWriteReg (TLAN7800Device *pThis, u32 nIndex, u32 nValue); boolean LAN7800DeviceReadReg (TLAN7800Device *pThis, u32 nIndex, u32 *pValue); static const char FromLAN7800[] = "lan7800"; // starting at 10, to be sure to not collide with smsc951x driver static unsigned s_nDeviceNumber = 10; void LAN7800Device (TLAN7800Device *pThis, TUSBDevice *pDevice) { assert (pThis != 0); USBDeviceCopy (&pThis->m_USBDevice, pDevice); pThis->m_USBDevice.Configure = LAN7800DeviceConfigure; pThis->m_pEndpointBulkIn = 0; pThis->m_pEndpointBulkOut = 0; pThis->m_pTxBuffer = 0; pThis->m_pTxBuffer = malloc (FRAME_BUFFER_SIZE); assert (pThis->m_pTxBuffer != 0); } void _LAN7800Device (TLAN7800Device *pThis) { assert (pThis != 0); if (pThis->m_pTxBuffer != 0) { free (pThis->m_pTxBuffer); pThis->m_pTxBuffer = 0; } if (pThis->m_pEndpointBulkOut != 0) { _USBEndpoint (pThis->m_pEndpointBulkOut); free (pThis->m_pEndpointBulkOut); pThis->m_pEndpointBulkOut = 0; } if (pThis->m_pEndpointBulkIn != 0) { _USBEndpoint (pThis->m_pEndpointBulkIn); free (pThis->m_pEndpointBulkIn); pThis->m_pEndpointBulkIn = 0; } _USBDevice (&pThis->m_USBDevice); } boolean LAN7800DeviceConfigure (TUSBDevice *pUSBDevice) { TLAN7800Device *pThis = (TLAN7800Device *) pUSBDevice; assert (pThis != 0); // check USB configuration const TUSBConfigurationDescriptor *pConfigDesc = (TUSBConfigurationDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_CONFIGURATION); if ( pConfigDesc == 0 || pConfigDesc->bNumInterfaces != 1) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromLAN7800); return FALSE; } const TUSBInterfaceDescriptor *pInterfaceDesc = (TUSBInterfaceDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_INTERFACE); if ( pInterfaceDesc == 0 || pInterfaceDesc->bInterfaceNumber != 0x00 || pInterfaceDesc->bAlternateSetting != 0x00 || pInterfaceDesc->bNumEndpoints != 3) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromLAN7800); return FALSE; } const TUSBEndpointDescriptor *pEndpointDesc; while ((pEndpointDesc = (TUSBEndpointDescriptor *) USBDeviceGetDescriptor (&pThis->m_USBDevice, DESCRIPTOR_ENDPOINT)) != 0) { if ((pEndpointDesc->bmAttributes & 0x3F) == 0x02) // Bulk { if ((pEndpointDesc->bEndpointAddress & 0x80) == 0x80) // Input { if (pThis->m_pEndpointBulkIn != 0) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromLAN7800); return FALSE; } pThis->m_pEndpointBulkIn = (TUSBEndpoint *) malloc (sizeof (TUSBEndpoint)); assert (pThis->m_pEndpointBulkIn); USBEndpoint2 (pThis->m_pEndpointBulkIn, &pThis->m_USBDevice, pEndpointDesc); } else // Output { if (pThis->m_pEndpointBulkOut != 0) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromLAN7800); return FALSE; } pThis->m_pEndpointBulkOut = (TUSBEndpoint *) malloc (sizeof (TUSBEndpoint)); assert (pThis->m_pEndpointBulkOut); USBEndpoint2 (pThis->m_pEndpointBulkOut, &pThis->m_USBDevice, pEndpointDesc); } } } if ( pThis->m_pEndpointBulkIn == 0 || pThis->m_pEndpointBulkOut == 0) { USBDeviceConfigurationError (&pThis->m_USBDevice, FromLAN7800); return FALSE; } if (!USBDeviceConfigure (&pThis->m_USBDevice)) { LogWrite (FromLAN7800, LOG_ERROR, "Cannot set configuration"); return FALSE; } // check chip ID u32 nValue; if ( !LAN7800DeviceReadReg (pThis, ID_REV, &nValue) || (nValue & ID_REV_CHIP_ID_MASK) >> 16 != ID_REV_CHIP_ID_7800) { LogWrite (FromLAN7800, LOG_ERROR, "Invalid chip ID (0x%X)", (nValue & ID_REV_CHIP_ID_MASK) >> 16); return FALSE; } // init hardware // HW reset if ( !LAN7800DeviceReadWriteReg (pThis, HW_CFG, HW_CFG_LRST, ~0U) || !LAN7800DeviceWaitReg (pThis, HW_CFG, HW_CFG_LRST, 0)) { LogWrite (FromLAN7800, LOG_ERROR, "HW reset failed"); return FALSE; } if (!LAN7800DeviceInitMACAddress (pThis)) { LogWrite (FromLAN7800, LOG_ERROR, "Cannot init MAC address"); return FALSE; } // for USB high speed if ( !LAN7800DeviceWriteReg (pThis, BURST_CAP, DEFAULT_BURST_CAP_SIZE / HS_USB_PKT_SIZE) || !LAN7800DeviceWriteReg (pThis, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY)) { return FALSE; } // enable the LEDs and SEF mode if (!LAN7800DeviceReadWriteReg (pThis, HW_CFG, HW_CFG_LED0_EN | HW_CFG_LED1_EN, ~HW_CFG_MEF)) { return FALSE; } // enable burst CAP, disable NAK on RX FIFO empty if (!LAN7800DeviceReadWriteReg (pThis, USB_CFG0, USB_CFG_BCE, ~USB_CFG_BIR)) { return FALSE; } // set FIFO sizes if ( !LAN7800DeviceWriteReg (pThis, FCT_RX_FIFO_END, (MAX_RX_FIFO_SIZE - 512) / 512) || !LAN7800DeviceWriteReg (pThis, FCT_TX_FIFO_END, (MAX_TX_FIFO_SIZE - 512) / 512)) { return FALSE; } // interrupt EP is not used if ( !LAN7800DeviceWriteReg (pThis, INT_EP_CTL, 0) || !LAN7800DeviceWriteReg (pThis, INT_STS, INT_STS_CLEAR_ALL)) { return FALSE; } // disable flow control if ( !LAN7800DeviceWriteReg (pThis, FLOW, 0) || !LAN7800DeviceWriteReg (pThis, FCT_FLOW, 0)) { return FALSE; } // init receive filtering engine if (!LAN7800DeviceReadWriteReg (pThis, RFE_CTL, RFE_CTL_BCAST_EN | RFE_CTL_DA_PERFECT, ~0U)) { return FALSE; } // PHY reset if ( !LAN7800DeviceReadWriteReg (pThis, PMT_CTL, PMT_CTL_PHY_RST, ~0U) || !LAN7800DeviceWaitReg (pThis, PMT_CTL, PMT_CTL_PHY_RST | PMT_CTL_READY, PMT_CTL_READY)) { LogWrite (FromLAN7800, LOG_ERROR, "PHY reset failed"); return FALSE; } // enable AUTO negotiation if (!LAN7800DeviceReadWriteReg (pThis, MAC_CR, MAC_CR_AUTO_DUPLEX | MAC_CR_AUTO_SPEED, ~0U)) { return FALSE; } // enable TX if ( !LAN7800DeviceReadWriteReg (pThis, MAC_TX, MAC_TX_TXEN, ~0U) || !LAN7800DeviceReadWriteReg (pThis, FCT_TX_CTL, FCT_TX_CTL_EN, ~0U)) { return FALSE; } // enable RX if ( !LAN7800DeviceReadWriteReg (pThis, MAC_RX, (MAX_RX_FRAME_SIZE << MAC_RX_MAX_SIZE_SHIFT) | MAC_RX_RXEN, ~MAC_RX_MAX_SIZE_MASK) || !LAN7800DeviceReadWriteReg (pThis, FCT_RX_CTL, FCT_RX_CTL_EN, ~0U)) { return FALSE; } if (!LAN7800DeviceInitPHY (pThis)) { LogWrite (FromLAN7800, LOG_ERROR, "Cannot init PHY"); return FALSE; } TString DeviceName; String (&DeviceName); StringFormat (&DeviceName, "eth%u", s_nDeviceNumber++); DeviceNameServiceAddDevice (DeviceNameServiceGet (), StringGet (&DeviceName), pThis, FALSE); _String (&DeviceName); return TRUE; } TMACAddress *LAN7800DeviceGetMACAddress (TLAN7800Device *pThis) { assert (pThis != 0); return &pThis->m_MACAddress; } boolean LAN7800DeviceSendFrame (TLAN7800Device *pThis, const void *pBuffer, unsigned nLength) { assert (pThis != 0); if (nLength > FRAME_BUFFER_SIZE-TX_HEADER_SIZE) { return FALSE; } assert (pThis->m_pTxBuffer != 0); assert (pBuffer != 0); memcpy (pThis->m_pTxBuffer+TX_HEADER_SIZE, pBuffer, nLength); *(u32 *) &pThis->m_pTxBuffer[0] = (nLength & TX_CMD_A_LEN_MASK) | TX_CMD_A_FCS; *(u32 *) &pThis->m_pTxBuffer[4] = 0; assert (pThis->m_pEndpointBulkOut != 0); return DWHCIDeviceTransfer (USBDeviceGetHost (&pThis->m_USBDevice), pThis->m_pEndpointBulkOut, pThis->m_pTxBuffer, nLength+TX_HEADER_SIZE) >= 0; } boolean LAN7800DeviceReceiveFrame (TLAN7800Device *pThis, void *pBuffer, unsigned *pResultLength) { assert (pThis != 0); assert (pThis->m_pEndpointBulkIn != 0); assert (pBuffer != 0); TUSBRequest URB; USBRequest (&URB, pThis->m_pEndpointBulkIn, pBuffer, FRAME_BUFFER_SIZE, 0); if (!DWHCIDeviceSubmitBlockingRequest (USBDeviceGetHost (&pThis->m_USBDevice), &URB)) { _USBRequest (&URB); return FALSE; } u32 nResultLength = USBRequestGetResultLength (&URB); if (nResultLength < RX_HEADER_SIZE) { _USBRequest (&URB); return FALSE; } u32 nRxStatus = *(u32 *) pBuffer; // RX command A if (nRxStatus & RX_CMD_A_RED) { LogWrite (FromLAN7800, LOG_WARNING, "RX error (status 0x%X)", nRxStatus); _USBRequest (&URB); return FALSE; } u32 nFrameLength = nRxStatus & RX_CMD_A_LEN_MASK; assert (nFrameLength == nResultLength-RX_HEADER_SIZE); assert (nFrameLength > 4); if (nFrameLength <= 4) { _USBRequest (&URB); return FALSE; } nFrameLength -= 4; // ignore FCS //LogWrite (FromLAN7800, LOG_DEBUG, "Frame received (status 0x%X)", nRxStatus); memcpy (pBuffer, (u8 *) pBuffer + RX_HEADER_SIZE, nFrameLength); // overwrite RX command A..C assert (pResultLength != 0); *pResultLength = nFrameLength; _USBRequest (&URB); return TRUE; } boolean LAN7800DeviceIsLinkUp (TLAN7800Device *pThis) { assert (pThis != 0); u16 usPHYModeStatus; if (!LAN7800DevicePHYRead (pThis, 0x01, &usPHYModeStatus)) { return FALSE; } return usPHYModeStatus & (1 << 2) ? TRUE : FALSE; } boolean LAN7800DeviceInitMACAddress (TLAN7800Device *pThis) { assert (pThis != 0); u8 MACAddress[MAC_ADDRESS_SIZE]; if (!GetMACAddress (MACAddress)) { return FALSE; } MACAddressSet (&pThis->m_MACAddress, MACAddress); u32 nMACAddressLow = (u32) MACAddress[0] | ((u32) MACAddress[1] << 8) | ((u32) MACAddress[2] << 16) | ((u32) MACAddress[3] << 24); u32 nMACAddressHigh = (u32) MACAddress[4] | ((u32) MACAddress[5] << 8); if ( !LAN7800DeviceWriteReg (pThis, RX_ADDRL, nMACAddressLow) || !LAN7800DeviceWriteReg (pThis, RX_ADDRH, nMACAddressHigh)) { return FALSE; } // set perfect filter entry for own MAC address if ( !LAN7800DeviceWriteReg (pThis, MAF_LO (0), nMACAddressLow) || !LAN7800DeviceWriteReg (pThis, MAF_HI (0), nMACAddressHigh | MAF_HI_VALID)) { return FALSE; } TString MACString; String (&MACString); MACAddressFormat (&pThis->m_MACAddress, &MACString); LogWrite (FromLAN7800, LOG_DEBUG, "MAC address is %s", StringGet (&MACString)); _String (&MACString); return TRUE; } boolean LAN7800DeviceInitPHY (TLAN7800Device *pThis) { assert (pThis != 0); // Change LED defaults: // orange = link1000/activity // green = link10/link100/activity // led: 0=link/activity 1=link1000/activity // 2=link100/activity 3=link10/activity // 4=link100/1000/activity 5=link10/1000/activity // 6=link10/100/activity 14=off 15=on u16 usLEDModeSel; if (!LAN7800DevicePHYRead (pThis, 0x1D, &usLEDModeSel)) { return FALSE; } usLEDModeSel &= ~0xFF; usLEDModeSel |= 1 << 0; usLEDModeSel |= 6 << 4; return LAN7800DevicePHYWrite (pThis, 0x1D, usLEDModeSel); } boolean LAN7800DevicePHYWrite (TLAN7800Device *pThis, u8 uchIndex, u16 usValue) { assert (pThis != 0); assert (uchIndex <= 30); if ( !LAN7800DeviceWaitReg (pThis, MII_ACC, MII_ACC_MII_BUSY, 0) || !LAN7800DeviceWriteReg (pThis, MII_DATA, usValue)) { return FALSE; } // set the address, index & direction (write to PHY) u32 nMIIAccess = (PHY_ADDRESS << MII_ACC_PHY_ADDR_SHIFT) & MII_ACC_PHY_ADDR_MASK; nMIIAccess |= ((u32) uchIndex << MII_ACC_MIIRINDA_SHIFT) & MII_ACC_MIIRINDA_MASK; nMIIAccess |= MII_ACC_MII_WRITE | MII_ACC_MII_BUSY; if (!LAN7800DeviceWriteReg (pThis, MII_ACC, nMIIAccess)) { return FALSE; } return LAN7800DeviceWaitReg (pThis, MII_ACC, MII_ACC_MII_BUSY, 0); } boolean LAN7800DevicePHYRead (TLAN7800Device *pThis, u8 uchIndex, u16 *pValue) { assert (pThis != 0); assert (uchIndex <= 30); if (!LAN7800DeviceWaitReg (pThis, MII_ACC, MII_ACC_MII_BUSY, 0)) { return FALSE; } // set the address, index & direction (read from PHY) u32 nMIIAccess = (PHY_ADDRESS << MII_ACC_PHY_ADDR_SHIFT) & MII_ACC_PHY_ADDR_MASK; nMIIAccess |= ((u32) uchIndex << MII_ACC_MIIRINDA_SHIFT) & MII_ACC_MIIRINDA_MASK; nMIIAccess |= MII_ACC_MII_READ | MII_ACC_MII_BUSY; u32 nValue; if ( !LAN7800DeviceWriteReg (pThis, MII_ACC, nMIIAccess) || !LAN7800DeviceWaitReg (pThis, MII_ACC, MII_ACC_MII_BUSY, 0) || !LAN7800DeviceReadReg (pThis, MII_DATA, &nValue)) { return FALSE; } assert (pValue != 0); *pValue = nValue & MII_DATA_MASK; return TRUE; } // wait until register 'nIndex' has value 'nCompare' with mask 'nMask' applied, // check the register each millisecond, timeout after one second boolean LAN7800DeviceWaitReg (TLAN7800Device *pThis, u32 nIndex, u32 nMask, u32 nCompare) { assert (pThis != 0); unsigned nTries = 1000; u32 nValue; do { MsDelay (1); if (--nTries == 0) { return FALSE; } if (!LAN7800DeviceReadReg (pThis, nIndex, &nValue)) { return FALSE; } } while ((nValue & nMask) != nCompare); return TRUE; } boolean LAN7800DeviceReadWriteReg (TLAN7800Device *pThis, u32 nIndex, u32 nOrMask, u32 nAndMask) { assert (pThis != 0); u32 nValue; if (!LAN7800DeviceReadReg (pThis, nIndex, &nValue)) { return FALSE; } nValue &= nAndMask; nValue |= nOrMask; return LAN7800DeviceWriteReg (pThis, nIndex, nValue); } boolean LAN7800DeviceWriteReg (TLAN7800Device *pThis, u32 nIndex, u32 nValue) { assert (pThis != 0); if (DWHCIDeviceControlMessage (USBDeviceGetHost (&pThis->m_USBDevice), USBDeviceGetEndpoint0 (&pThis->m_USBDevice), REQUEST_OUT | REQUEST_VENDOR, WRITE_REGISTER, 0, nIndex, &nValue, sizeof nValue) < 0) { LogWrite (FromLAN7800, LOG_WARNING, "Cannot write register 0x%X", nIndex); return FALSE; } return TRUE; } boolean LAN7800DeviceReadReg (TLAN7800Device *pThis, u32 nIndex, u32 *pValue) { assert (pThis != 0); if (DWHCIDeviceControlMessage (USBDeviceGetHost (&pThis->m_USBDevice), USBDeviceGetEndpoint0 (&pThis->m_USBDevice), REQUEST_IN | REQUEST_VENDOR, READ_REGISTER, 0, nIndex, pValue, sizeof *pValue) != (int) sizeof *pValue) { LogWrite (FromLAN7800, LOG_WARNING, "Cannot read register 0x%X", nIndex); return FALSE; } return TRUE; }