//***************************************************************************** // // luminaryif.c - Ethernet Interface File for lwIP TCP/IP Stack // //***************************************************************************** #include #include #include #include #include #include #include #include #include #include #include "lwipopts.h" #include "luminaryif.h" #define MAX_ADDR_LEN 6 struct net_device { /* inherit from ethernet device */ struct eth_device parent; /* interface address info. */ rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */ }; static struct net_device luminaryif_dev_entry; static struct net_device *luminaryif_dev = &luminaryif_dev_entry; static struct rt_semaphore tx_sem; //***************************************************************************** // // Sanity Check: This module will NOT work if the following defines // are incorrect. // //***************************************************************************** #if (PBUF_LINK_HLEN != 16) #error "Incorrect PBUF_LINK_HLEN specified!" #endif #if (ETH_PAD_SIZE != 2) #error "Incorrect ETH_PAD_SIZE specified!" #endif #if (PBUF_POOL_BUFSIZE % 4) #error "PBUF_POOL_BUFSIZE must be modulo 4!" #endif /* RT-Thread Device Interface */ /* initialize the interface */ //***************************************************************************** // // Low-Level initialization function for the Ethernet Controller. // //***************************************************************************** rt_err_t luminaryif_init(rt_device_t dev) { unsigned long ulTemp; // // Disable all Ethernet Interrupts. // EthernetIntDisable(ETH_BASE, (ETH_INT_PHY | ETH_INT_MDIO | ETH_INT_RXER | ETH_INT_RXOF | ETH_INT_TX | ETH_INT_TXER | ETH_INT_RX)); ulTemp = EthernetIntStatus(ETH_BASE, false); EthernetIntClear(ETH_BASE, ulTemp); // // Initialize the Ethernet Controller. // EthernetInitExpClk(ETH_BASE, SysCtlClockGet()); // // Configure the Ethernet Controller for normal operation. // - Enable TX Duplex Mode // - Enable TX Padding // - Enable TX CRC Generation // EthernetConfigSet(ETH_BASE, (ETH_CFG_TX_DPLXEN | ETH_CFG_TX_CRCEN | ETH_CFG_TX_PADEN)); // // Enable the Ethernet Controller transmitter and receiver. // EthernetEnable(ETH_BASE); // // Enable the Ethernet Interrupt handler. // IntEnable(INT_ETH); // // Enable Ethernet TX and RX Packet Interrupts. // EthernetIntEnable(ETH_BASE, ETH_INT_RX | ETH_INT_TX); return RT_EOK; } void luminaryif_isr(void) { unsigned long ulTemp; // // Read and Clear the interrupt. // ulTemp = EthernetIntStatus(ETH_BASE, false); EthernetIntClear(ETH_BASE, ulTemp); // // Check to see if an RX Interrupt has occured. // if (ulTemp & ETH_INT_RX) { // // Indicate that a packet has been received. // rt_err_t result; /* a frame has been received */ result = eth_device_ready((struct eth_device *)&(luminaryif_dev->parent)); if (result != RT_EOK) rt_set_errno(-RT_ERROR); // // Disable Ethernet RX Interrupt. // EthernetIntDisable(ETH_BASE, ETH_INT_RX); } if (ulTemp & ETH_INT_TX) { /* A frame has been transmitted. */ rt_sem_release(&tx_sem); } } /* control the interface */ rt_err_t luminaryif_control(rt_device_t dev, int cmd, void *args) { switch (cmd) { case NIOCTL_GADDR: /* get mac address */ if (args) rt_memcpy(args, luminaryif_dev_entry.dev_addr, 6); else return -RT_ERROR; break; default: break; } return RT_EOK; } /* Open the ethernet interface */ rt_err_t luminaryif_open(rt_device_t dev, rt_uint16_t oflag) { return RT_EOK; } /* Close the interface */ rt_err_t luminaryif_close(rt_device_t dev) { return RT_EOK; } /* Read */ rt_size_t luminaryif_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { rt_set_errno(-RT_ENOSYS); return 0; } /* Write */ rt_size_t luminaryif_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) { rt_set_errno(-RT_ENOSYS); return 0; } //**************************************************************************** // // Low-Level transmit routine. Should do the actual transmission of the // packet. The packet is contained in the pbuf that is passed to the function. // This pbuf might be chained. // //**************************************************************************** rt_err_t luminaryif_tx(rt_device_t dev, struct pbuf *p) { int iBuf; unsigned char *pucBuf; unsigned long *pulBuf; struct pbuf *q; int iGather; unsigned long ulGather; unsigned char *pucGather; unsigned long ulTemp; /* lock tx operation */ rt_sem_take(&tx_sem, RT_WAITING_FOREVER); // // Wait for space available in the TX FIFO. // while (!EthernetSpaceAvail(ETH_BASE)) { } // // Fill in the first two bytes of the payload data (configured as padding // with ETH_PAD_SIZE = 2) with the total length of the payload data // (minus the Ethernet MAC layer header). // *((unsigned short *)(p->payload)) = p->tot_len - 16; // // Initialize the gather register. // iGather = 0; pucGather = (unsigned char *)&ulGather; ulGather = 0; // // Copy data from the pbuf(s) into the TX Fifo. // for (q = p; q != NULL; q = q->next) { // // Intialize a char pointer and index to the pbuf payload data. // pucBuf = (unsigned char *)q->payload; iBuf = 0; // // If the gather buffer has leftover data from a previous pbuf // in the chain, fill it up and write it to the Tx FIFO. // while ((iBuf < q->len) && (iGather != 0)) { // // Copy a byte from the pbuf into the gather buffer. // pucGather[iGather] = pucBuf[iBuf++]; // // Increment the gather buffer index modulo 4. // iGather = ((iGather + 1) % 4); } // // If the gather index is 0 and the pbuf index is non-zero, // we have a gather buffer to write into the Tx FIFO. // if ((iGather == 0) && (iBuf != 0)) { HWREG(ETH_BASE + MAC_O_DATA) = ulGather; ulGather = 0; } // // Copy words of pbuf data into the Tx FIFO, but don't go past // the end of the pbuf. // if ((iBuf % 4) != 0) { while ((iBuf + 4) <= q->len) { ulTemp = (pucBuf[iBuf++] << 0); ulTemp |= (pucBuf[iBuf++] << 8); ulTemp |= (pucBuf[iBuf++] << 16); ulTemp |= (pucBuf[iBuf++] << 24); HWREG(ETH_BASE + MAC_O_DATA) = ulTemp; } } else { // // Initialze a long pointer into the pbuf for 32-bit access. // pulBuf = (unsigned long *)&pucBuf[iBuf]; while ((iBuf + 4) <= q->len) { HWREG(ETH_BASE + MAC_O_DATA) = *pulBuf++; iBuf += 4; } } // // Check if leftover data in the pbuf and save it in the gather // buffer for the next time. // while (iBuf < q->len) { // // Copy a byte from the pbuf into the gather buffer. // pucGather[iGather] = pucBuf[iBuf++]; // // Increment the gather buffer index modulo 4. // iGather = ((iGather + 1) % 4); } } // // Send any leftover data to the FIFO. // HWREG(ETH_BASE + MAC_O_DATA) = ulGather; // // Wakeup the transmitter. // HWREG(ETH_BASE + MAC_O_TR) = MAC_TR_NEWTX; #if LINK_STATS lwip_stats.link.xmit++; #endif return (ERR_OK); } //***************************************************************************** // // Low-Level receive routine. Should allocate a pbuf and transfer the bytes // of the incoming packet from the interface into the pbuf. // //***************************************************************************** struct pbuf *luminaryif_rx(rt_device_t dev) { struct pbuf *p, *q; u16_t len; unsigned long ulTemp; int i; unsigned long *ptr; if (!EthernetPacketAvail(ETH_BASE)) { // // Enable Ethernet RX Interrupt. // EthernetIntEnable(ETH_BASE, ETH_INT_RX); return (NULL); } // // Obtain the size of the packet and put it into the "len" variable. // Note: The length returned in the FIFO length position includes the // two bytes for the length + the 4 bytes for the FCS. // ulTemp = HWREG(ETH_BASE + MAC_O_DATA); len = ulTemp & 0xFFFF; // // We allocate a pbuf chain of pbufs from the pool. // p = pbuf_alloc(PBUF_LINK, len, PBUF_RAM); if (p != NULL) { // // Place the first word into the first pbuf location. // *(unsigned long *)p->payload = ulTemp; p->payload = (char *)(p->payload) + 4; p->len -= 4; // // Process all but the last buffer in the pbuf chain. // q = p; while (q != NULL) { // // Setup a byte pointer into the payload section of the pbuf. // ptr = q->payload; // // Read data from FIFO into the current pbuf // (assume pbuf length is modulo 4) // for (i = 0; i < q->len; i += 4) { *ptr++ = HWREG(ETH_BASE + MAC_O_DATA); } // // Link in the next pbuf in the chain. // q = q->next; } // // Restore the first pbuf parameters to their original values. // p->payload = (char *)(p->payload) - 4; p->len += 4; #if LINK_STATS lwip_stats.link.recv++; #endif } else { // // Just read all of the remaining data from the FIFO and dump it. // for (i = 4; i < len; i += 4) { ulTemp = HWREG(ETH_BASE + MAC_O_DATA); } #if LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif // // Enable Ethernet RX Interrupt. // EthernetIntEnable(ETH_BASE, ETH_INT_RX); } return (p); } int rt_hw_luminaryif_init(void) { rt_err_t result; unsigned long ulUser0, ulUser1; /* Enable and Reset the Ethernet Controller. */ SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH); SysCtlPeripheralReset(SYSCTL_PERIPH_ETH); /* Enable Port F for Ethernet LEDs. LED0 Bit 3 Output LED1 Bit 2 Output */ SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF); /* GPIODirModeSet and GPIOPadConfigSet */ GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3); GPIOPinConfigure(GPIO_PF2_LED1); GPIOPinConfigure(GPIO_PF3_LED0); FlashUserSet(0x00371200, 0x00563412); /* OUI:00-12-37 (hex) Texas Instruments, only for test */ /* Configure the hardware MAC address */ FlashUserGet(&ulUser0, &ulUser1); if ((ulUser0 == 0xffffffff) || (ulUser1 == 0xffffffff)) { rt_kprintf("Fatal error in geting MAC address\n"); } /* init rt-thread device interface */ luminaryif_dev_entry.parent.parent.init = luminaryif_init; luminaryif_dev_entry.parent.parent.open = luminaryif_open; luminaryif_dev_entry.parent.parent.close = luminaryif_close; luminaryif_dev_entry.parent.parent.read = luminaryif_read; luminaryif_dev_entry.parent.parent.write = luminaryif_write; luminaryif_dev_entry.parent.parent.control = luminaryif_control; luminaryif_dev_entry.parent.eth_rx = luminaryif_rx; luminaryif_dev_entry.parent.eth_tx = luminaryif_tx; /* Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC address needed to program the hardware registers, then program the MAC address into the Ethernet Controller registers. */ luminaryif_dev_entry.dev_addr[0] = ((ulUser0 >> 0) & 0xff); luminaryif_dev_entry.dev_addr[1] = ((ulUser0 >> 8) & 0xff); luminaryif_dev_entry.dev_addr[2] = ((ulUser0 >> 16) & 0xff); luminaryif_dev_entry.dev_addr[3] = ((ulUser1 >> 0) & 0xff); luminaryif_dev_entry.dev_addr[4] = ((ulUser1 >> 8) & 0xff); luminaryif_dev_entry.dev_addr[5] = ((ulUser1 >> 16) & 0xff); /* Program the hardware with it's MAC address (for filtering). */ EthernetMACAddrSet(ETH_BASE, luminaryif_dev_entry.dev_addr); rt_sem_init(&tx_sem, "emac", 1, RT_IPC_FLAG_FIFO); result = eth_device_init(&(luminaryif_dev->parent), "E0"); return result; }