summaryrefslogtreecommitdiff
path: root/uLan
diff options
context:
space:
mode:
authorKinsey Moore <kinsey.moore@oarcorp.com>2022-04-14 12:32:14 -0500
committerVijay Kumar Banerjee <vijay@rtems.org>2022-06-01 21:23:41 -0600
commit0b367b535083535896607710bbe8a46f8f6e0c74 (patch)
treeab3a45915a3a3400365c9842a2dd9a1647b510dc /uLan
parent5ad5279ca879c3cf0faf3141c84067bdf232c3a2 (diff)
lwip: Split sources into origin directories
Moving forward, each origin directory should have its own top-level COPYING.origin file to describe its license as well as a ORIGIN.origin file to describe where the code is sourced from.
Diffstat (limited to 'uLan')
-rw-r--r--uLan/ports/driver/tms570_emac/eth_lwip.c188
-rw-r--r--uLan/ports/driver/tms570_emac/eth_lwip.h100
-rw-r--r--uLan/ports/driver/tms570_emac/eth_lwip_default.h48
-rw-r--r--uLan/ports/driver/tms570_emac/phy_dp83848h.c179
-rw-r--r--uLan/ports/driver/tms570_emac/phy_dp83848h.h225
-rw-r--r--uLan/ports/driver/tms570_emac/ti_drv_emac.h472
-rw-r--r--uLan/ports/driver/tms570_emac/ti_drv_mdio.h165
-rw-r--r--uLan/ports/driver/tms570_emac/tms570_emac.h117
-rw-r--r--uLan/ports/driver/tms570_emac/tms570_netif.c1227
-rw-r--r--uLan/ports/driver/tms570_emac/tms570_netif.h60
-rw-r--r--uLan/ports/os/lwipopts.h64
-rw-r--r--uLan/ports/os/rtems/arch/cc.h177
-rw-r--r--uLan/ports/os/rtems/arch/perf.h12
-rw-r--r--uLan/ports/os/rtems/arch/sys_arch.c378
-rw-r--r--uLan/ports/os/rtems/arch/sys_arch.h108
15 files changed, 3520 insertions, 0 deletions
diff --git a/uLan/ports/driver/tms570_emac/eth_lwip.c b/uLan/ports/driver/tms570_emac/eth_lwip.c
new file mode 100644
index 0000000..b1ae4bb
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/eth_lwip.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2013, 2015 Czech Technical University in Prague
+ * Czech Republic
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Premysl Houdek <houdepre@fel.cvut.cz>
+ * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Industrial Informatics Group, FEE, Czech Technical University in Prague
+ *
+ * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal
+ */
+
+//#define DEBUG 1
+#include "lwip/tcpip.h" /* includes - lwip/opt.h, lwip/api_msg.h, lwip/netifapi.h, lwip/pbuf.h, lwip/api.h, lwip/sys.h, lwip/timers.h, lwip/netif.h */
+#include "lwip/stats.h"
+#include "lwip/dhcp.h"
+#include "lwip/netifapi.h"
+#include "netif/etharp.h" /* includes - lwip/ip.h, lwip/netif.h, lwip/ip_addr.h, lwip/pbuf.h */
+#include "eth_lwip_default.h"
+#include "eth_lwip.h"
+#include "tms570_netif.h"
+#include <stdio.h>
+
+/* The lwIP network interface structure for the Ethernet EMAC. */
+#ifndef MAX_EMAC_INSTANCE
+#define MAX_EMAC_INSTANCE 1
+#endif /*MAX_EMAC_INSTANCE*/
+
+#define SUCCESS ERR_OK
+#define FAILURE ERR_IF
+
+static struct netif eth_lwip_netifs[MAX_EMAC_INSTANCE];
+static void eth_lwip_conv_IP_decimal_Str(ip_addr_t ip, uint8_t *ipStr);
+
+
+void
+eth_lwip_get_dhcp_info(void)
+{
+ struct netif *netif = eth_lwip_get_netif(0);
+
+ if (dhcp_supplied_address(netif)) {
+ uint8_t ipString[16]; // FIXME change the functions to use char
+ eth_lwip_conv_IP_decimal_Str(netif->ip_addr, ipString);
+ printf("Address: %s\n", ipString);
+ eth_lwip_conv_IP_decimal_Str(netif->netmask, ipString);
+ printf("Netmask: %s\n", ipString);
+ eth_lwip_conv_IP_decimal_Str(netif->gw, ipString);
+ printf("Gateway: %s\n", ipString);
+ } else {
+ printf("dhcp not bound\n");
+ }
+}
+
+int8_t
+eth_lwip_init(uint8_t *mac_addr)
+{
+ unsigned int instance_number = 0;
+ int8_t retVal = SUCCESS;
+
+
+ ip4_addr_t ip_addr;
+ ip4_addr_t net_mask;
+ ip4_addr_t gw_addr;
+ struct netif *netif = &eth_lwip_netifs[instance_number];
+ struct netif *netif_tmp;
+ u8_t default_mac[MAC_ADDR_LEN] = ETH_MAC_ADDR;
+
+ if (mac_addr == NULL)
+ mac_addr = default_mac; /* use default MAC */
+
+ eth_lwip_set_hwaddr(netif, mac_addr);
+ tcpip_init(NULL, NULL);
+
+#if STATIC_IP_ADDRESS
+ ip_addr.addr = htonl(ETH_IP_ADDR);
+ net_mask.addr = htonl(ETH_NETMASK);
+ gw_addr.addr = htonl(ETH_GW);
+#else
+ ip_addr.addr = 0;
+ net_mask.addr = 0;
+ gw_addr.addr = 0;
+#endif
+
+ netif_tmp = netif_add(netif, &ip_addr, &net_mask, &gw_addr,
+ NULL, ETH_LWIP_INIT_NETIF_FNC, tcpip_input);
+
+ if (netif_tmp == NULL)
+ return NETIF_ADD_ERR;
+
+ netif_set_default(netif);
+ netifapi_netif_set_up(netif);
+#if !STATIC_IP_ADDRESS
+ netifapi_dhcp_start(netif);
+#endif
+
+ return retVal;
+}
+
+int
+eth_lwip_get_netif_status_cmd(int argc, char *arg[])
+{
+ stats_display();
+ return 0;
+}
+
+struct netif *
+eth_lwip_get_netif(uint32_t instance_number)
+{
+ if (instance_number >= MAX_EMAC_INSTANCE)
+ return NULL;
+ return &eth_lwip_netifs[instance_number];
+}
+
+static void
+eth_lwip_conv_IP_decimal_Str(ip_addr_t ip, uint8_t *ipStr)
+{
+ uint32_t addr;
+ #if LWIP_IPV6
+ addr = ip.u_addr.ip4.addr;
+ #else
+ addr = ip.addr;
+ #endif
+
+ snprintf((char *)ipStr, 16, "%lu.%lu.%lu.%lu",
+ (addr >> 24), ((addr >> 16) & 0xff), ((addr >> 8) & 0xff), (addr & 0xff));
+}
+
+/*
+* Function to set the MAC address to the interface
+* @param inst_num the instance number
+*
+* @note mac_addr[0] is considered MSB
+*/
+void
+eth_lwip_set_hwaddr(struct netif *netif, uint8_t *mac_addr)
+{
+ int i;
+
+ /* set MAC hardware address */
+ for (i = 0; i < MAC_ADDR_LEN; i++) {
+ netif->hwaddr[i] = mac_addr[i];
+ }
+ netif->hwaddr_len = MAC_ADDR_LEN;
+
+#ifdef DEBUG
+ uint8_t macStr[18];
+ eth_lwip_get_hwaddr_str(netif, macStr);
+ printf("Setting MAC... %s\r\n", macStr);
+#endif
+}
+
+void
+eth_lwip_get_hwaddr_str(struct netif *netif, uint8_t *macStr)
+{
+ uint8_t index, outindex = 0;
+ char ch;
+
+ for (index = 0; index < netif->hwaddr_len; index++) {
+ if (index)
+ macStr[outindex++] = ':';
+ ch = (netif->hwaddr[index] >> 4);
+ macStr[outindex++] = (ch < 10) ? (ch + '0') : (ch - 10 + 'A');
+ ch = (netif->hwaddr[index] & 0xf);
+ macStr[outindex++] = (ch < 10) ? (ch + '0') : (ch - 10 + 'A');
+ }
+ macStr[outindex] = 0;
+}
diff --git a/uLan/ports/driver/tms570_emac/eth_lwip.h b/uLan/ports/driver/tms570_emac/eth_lwip.h
new file mode 100644
index 0000000..a9c0325
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/eth_lwip.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013, 2015 Czech Technical University in Prague
+ * Czech Republic
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Premysl Houdek <houdepre@fel.cvut.cz>
+ * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Industrial Informatics Group, FEE, Czech Technical University in Prague
+ *
+ * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal
+ */
+
+#ifndef __ETH_LWIP_H
+#define __ETH_LWIP_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include "lwip/netif.h"
+
+
+/**
+ * While scanning phy addresses no alive phy was found.
+ * Return value of rpp_eth_hw_init() function.
+ */
+#define NO_PHY_ALIVE -1
+/**
+ * Scanning default phy address, it was found it's not alive.
+ * Return value of rpp_eth_hw_init() function.
+ */
+#define DFLT_PHY_NOT_ALIVE -1
+/**
+ * When setting autonegotiation parameters to EMAC module, there was found impossible mode (usually on timeout of autonegotiation).
+ * Return value of rpp_eth_hw_init_postInit() function.
+ */
+#define UNKN_DUPLEX_MODE -2 /* this could mean that autonegotiation was not completed yet */
+/**
+ * Phy is down error.
+ * Return value of rpp_eth_init_postInit() function.
+ */
+#define PHY_LINK_DOWN -3
+
+/**
+ * LwIP netif couldn't be added, it is likely that there was an error during initialization of the hardware.
+ */
+#define NETIF_ADD_ERR -10 /* could be one of previous, except PHY_LINK_DOWN - currently */
+/**
+ * Memory requirements couldn't be satisfied.
+ */
+#define DHCP_MEM_ERR -11
+
+/**
+ * configures whether rpp_eth_get_macAddrStr() creates string with big or small latin letters
+ */
+#define MAC_BIG_LETTERS 1
+
+/**
+ * ETH module system startup initialization.
+ *
+ * Call this method before using this module.
+ * This method starts autonegotiation and doesn't check for end of autoneg.
+ * When eth module is about to be used, you have to run rpp_eth_init_postInit()
+ * first and you should check whether link is up.
+ *
+ * @return SUCCESS if initialization successful.\n
+ * FAILURE if module already initialized.
+ */
+int8_t eth_lwip_init(uint8_t *mac_addr);
+void eth_lwip_get_dhcp_info(void);
+int eth_lwip_get_netif_status_cmd(int argc, char *arg[]);
+void eth_lwip_set_hwaddr(struct netif *netif, uint8_t *mac_addr);
+void eth_lwip_get_hwaddr_str(struct netif *netif, uint8_t *macStr);
+struct netif *eth_lwip_get_netif(uint32_t instance_number);
+
+
+
+
+
+
+#endif /* __ETH_LWIP_H */
diff --git a/uLan/ports/driver/tms570_emac/eth_lwip_default.h b/uLan/ports/driver/tms570_emac/eth_lwip_default.h
new file mode 100644
index 0000000..6194d06
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/eth_lwip_default.h
@@ -0,0 +1,48 @@
+#ifndef __ETH_LWIP_DEFAULT_H
+#define __ETH_LWIP_DEFAULT_H
+
+/* #define DEBUG 1 */
+/* #define STATIC_IP_ADDRESS 1 */
+
+void tms570_eth_memp_avaible(int type);
+
+#define ETH_LWIP_INIT_NETIF_FNC tms570_eth_init_netif
+/*called from memp_free() when a memp pool was empty and an item is now available*/
+#define LWIP_HOOK_MEMP_AVAILABLE tms570_eth_memp_avaible
+
+/* this MAC address is used when user put NULL on the right place when calling postInit function */
+/**
+ * Default MAC address for interface.
+ */
+#define MAC_ADDR_LEN ETHARP_HWADDR_LEN
+
+#ifndef ETH_MAC_ADDR
+#define ETH_MAC_ADDR { 0x12 /* Unicast, Locally administered */, 0x34, 0x56, 0x78, 0x9A, 0xBC }
+#endif
+
+#if STATIC_IP_ADDRESS
+
+/**
+ * When static IP is configured in lwipopts.h, this IP address is used for interface.
+ */
+#ifndef ETH_IP_ADDR
+#define ETH_IP_ADDR 0xC0A8F701 /* 192.168.247.1 */
+#endif
+
+/**
+ * When static IP is configured in lwipopts.h, this NETMASK address is used for interface.
+ */
+#ifndef ETH_NETMASK
+#define ETH_NETMASK 0xFFFFFF00 /* 255.255.255.0 */
+#endif
+
+/**
+ * When static IP is configured in lwipopts.h, this Gateway address is used for interface.
+ */
+#ifndef ETH_GW
+#define ETH_GW 0xC0A8F7FE /* 192.168.247.254*/
+#endif
+
+#endif /* STATIC_IP_ADDRESS */
+
+#endif /* __ETH_LWIP_DEFAULT_H */
diff --git a/uLan/ports/driver/tms570_emac/phy_dp83848h.c b/uLan/ports/driver/tms570_emac/phy_dp83848h.c
new file mode 100644
index 0000000..d20f669
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/phy_dp83848h.c
@@ -0,0 +1,179 @@
+/*
+* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include "ti_drv_mdio.h"
+#include "phy_dp83848h.h"
+
+#ifndef TRUE
+/**
+ * Boolean definition for TRUE
+ */
+#define TRUE 1
+#endif
+
+
+#ifndef FALSE
+/**
+ * Boolean definition for FALSE
+ */
+#define FALSE 0
+#endif
+
+void
+PHY_reset(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr)
+{
+ volatile unsigned short regContent;
+
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, PHY_RESET_m);
+ while (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, &regContent) & PHY_RESET_m);
+}
+
+uint32_t
+PHY_partner_ability_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short *regContent)
+{
+ return (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ANLPAR, regContent));
+}
+
+uint32_t
+PHY_start_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal)
+{
+ volatile unsigned short regContent = 0;
+
+ /* Enable Auto Negotiation */
+ if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, &regContent) != TRUE) {
+ return FALSE;
+ }
+ regContent |= PHY_AUTONEG_EN_m;
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent); /* originally ...HY_BMCR, PHY_RESET_m | PHY_AUTONEG_EN_m); */
+
+ /* Write Auto Negotiation capabilities */
+ if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_ANAR, &regContent) != TRUE) {
+ return FALSE;
+ }
+ regContent |= advVal;
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_ANAR, regContent);
+
+ /* Start Auto Negotiation */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, &regContent);
+ regContent |= PHY_AUTONEG_REST;
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent);
+
+ return TRUE; /* request to PHY through EMAC for autonegotiation established */
+}
+
+uint32_t
+PHY_is_done_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr)
+{
+ volatile unsigned short regContent;
+
+ if (MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMSR, &regContent) != TRUE) {
+ return FALSE;
+ }
+ if ((regContent & PHY_A_NEG_COMPLETE_m) == 0)
+ return FALSE;
+ return TRUE;
+}
+
+uint32_t
+PHY_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal)
+{
+ if (PHY_start_auto_negotiate(mdioBaseAddr, phyAddr, advVal) == FALSE)
+ return FALSE;
+
+ while (PHY_is_done_auto_negotiate(mdioBaseAddr, phyAddr) == FALSE);
+
+ return TRUE;
+}
+
+uint32_t
+PHY_link_status_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, volatile uint32_t retries)
+{
+ volatile unsigned short linkStatus;
+ volatile uint32_t retVal = TRUE;
+
+ while (retVal == TRUE) {
+ /* Read the BSR of the PHY */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMSR, &linkStatus);
+
+ if (linkStatus & PHY_LINK_STATUS_m) {
+ break;
+ } else
+ {
+ (retries != 0) ? retries-- : (retVal = FALSE);
+ }
+ }
+
+ return retVal;
+}
+
+uint32_t
+PHY_RMII_mode_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr)
+{
+ volatile unsigned short regContent;
+
+ /* Read the RBR of the PHY */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_RBR, &regContent);
+ return (regContent & PHY_RMII_MODE);
+}
+
+void
+PHY_MII_mode_set(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, uint32_t mode)
+{
+ volatile unsigned short regContent;
+
+ /* Read the RBR of the PHY */
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_RBR, &regContent);
+ /* Write the RBR of the PHY */
+ regContent &= 0x1f;
+ regContent |= ( mode << 5 );
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_RBR, regContent);
+}
+
+void
+PHY_Power_Down(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr)
+{
+ volatile unsigned short regContent;
+
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, &regContent);
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent | PHY_POWERDOWN_m);
+}
+
+void
+PHY_Power_Up(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr)
+{
+ volatile unsigned short regContent;
+
+ MDIOPhyRegRead(mdioBaseAddr, phyAddr, PHY_BMCR, &regContent);
+ MDIOPhyRegWrite(mdioBaseAddr, phyAddr, PHY_BMCR, regContent & ~PHY_POWERDOWN_m);
+}
diff --git a/uLan/ports/driver/tms570_emac/phy_dp83848h.h b/uLan/ports/driver/tms570_emac/phy_dp83848h.h
new file mode 100644
index 0000000..58d9f04
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/phy_dp83848h.h
@@ -0,0 +1,225 @@
+/*
+* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#ifndef __DRV_PHY_H
+#define __DRV_PHY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ************************************************* */
+/* PHY - register offset definition */
+/* ************************************************* */
+#define PHY_BMCR 0x00u /* Basic Mode Control Register */ /*RW*/
+#define PHY_BMSR 0x01u /* Basic Mode Status Register */ /*RO*/
+#define PHY_IDR1 0x02u /* PHY Identifier Register #1 */ /*RO*/
+#define PHY_IDR2 0x03u /* PHY Identifier Register #2 */ /*RO*/
+#define PHY_ANAR 0x04u /* Auto-Negotiation Advertisement Register */ /*RW*/
+#define PHY_ANLPAR 0x05u /* Auto-Negotiation Link Partner Ability Register */ /*RW*/
+#define PHY_ANER 0x06u /* Auto-Negotiation Expansion Register */ /*RW*/
+#define PHY_ANNPTR 0x07u /* Auto-Negotiation Next Page TX */ /*RW*/
+/*Extended Registers*/
+#define PHY_STS 0x10u /* PHY Status Register */ /*RO*/
+#define PHY_RBR 0x17u /* RMII and Bypass Register */
+#define PHY_LEDCR 0x18u /* LED Direct Control Register */ /*RW*/
+#define PHY_PHYCR 0x19u /* PHY Control Register */ /*RW*/
+/* #define PHY_PHYCR2 0x1C */ /* PHY Control Register 2 */ /*RW*/ /* in doc offset 0x1C marked as RESERVED */
+#define PHY_EDCR 0x1Du /* Energy detect control register */ /*RW*/
+
+/* PHY_BMCR - bit position definition */
+#define PHY_RESET_m (1 << 15)
+#define PHY_LPBK_m (1 << 14)
+#define PHY_SPEED_m (1 << 13)
+#define PHY_AUTONEG_EN_m (1 << 12) /* ! */
+#define PHY_POWERDOWN_m (1 << 11)
+#define PHY_DUPLEX_m (1 << 8)
+#define PHY_AUTONEG_REST (1 << 9)
+
+/* PHY_BMSR - bit position definition */
+#define PHY_A_NEG_COMPLETE_m (1 << 5)
+#define PHY_A_NEG_ABLE_m (1 << 3)
+#define PHY_LINK_STATUS_m (1 << 2)
+
+/* PHY_ANAR & PHY_ANLPAR - bit position definition */
+#define PHY_PAUSE_ASYM (1 << 11)
+#define PHY_PAUSE_SYM (1 << 10)
+#define PHY_100BASET4_m (1 << 9)
+#define PHY_100BASETXDUPL_m (1 << 8)
+#define PHY_100BASETX_m (1 << 7)
+#define PHY_10BASETDUPL_m (1 << 6)
+#define PHY_10BASET_m (1 << 5)
+
+/* RBR */
+#define PHY_RMII_MODE (1 << 5) /* Reduced Media Independent Interface mode */
+#define PHY_MII_MODE (0) /* Standard Media Independent Interface mode */
+#define PHY_RMII_REV1_0 (1 << 4)
+#define PHY_RMII_REV1_2 (0)
+
+/* ************************************************* */
+/* API - function prototypes */
+/* ************************************************* */
+
+/**
+ * Resets PHY
+ *
+ * @param mdioBaseAddr Base Address of MDIO Module Megisters.
+ * @param phyAddr PHY Address (0-31).
+ *
+ * @note Software driver code must wait 3 μs following a software
+ * reset before allowing further serial MII operations with the DP83848H.
+ * This must be implemented in the layer above.
+ * @note Calling this function is blocking until PHY indicates the reset process is complete.
+ */
+void PHY_reset(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr);
+
+/**
+ * Reads link partner ability register from the PHY
+ *
+ * @param mdioBaseAddr Base Address of MDIO Module Megisters.
+ * @param phyAddr PHY Address (0-31).
+ * @param regContent The partner abilities of the EMAC.
+ *
+ * @return TRUE if reading succesful, FALSE if reading failed
+ */
+uint32_t PHY_partner_ability_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short *regContent);
+
+/**
+ * This function does Autonegotiates with the EMAC device connected
+ * to the PHY. It will wait till the autonegotiation completes.
+ *
+ * @param mdioBaseAddr Base Address of MDIO Module Megisters.
+ * @param phyAddr PHY Address (0-31).
+ * @param advValue Autonegotiation advertisement value \n
+ * advVal can take the following any OR combination of the values:
+ * PHY_100BASETXDUPL_m - full duplex capability for 100BaseTX
+ * PHY_100BASETX_m - half duplex capability for 100BaseTX
+ * PHY_10BASETDUPL_m - full duplex capability for 10BaseT
+ * PHY_10BASET_m - half duplex capability for 10BaseT
+ *
+ * @return TRUE if autonegotiation succesful, FALSE if autonegotiation failed
+ *
+ * @note this function is blocking, waits till link is established
+ */
+uint32_t PHY_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal);
+
+/**
+ * This function starts autonegotiaon with the EMAC device connected
+ * to the PHY. For examining, whether autonegotiation is done see
+ * PHY_start_auto_negotiate function.
+ *
+ * @param mdioBaseAddr Base Address of MDIO Module Megisters.
+ * @param phyAddr PHY Address (0-31).
+ * @param advValue Autonegotiation advertisement value \n
+ * advVal can take the following any OR combination of the values:
+ * PHY_100BASETXDUPL_m - full duplex capability for 100BaseTX
+ * PHY_100BASETX_m - half duplex capability for 100BaseTX
+ * PHY_10BASETDUPL_m - full duplex capability for 10BaseT
+ * PHY_10BASET_m - half duplex capability for 10BaseT
+ *
+ * @return TRUE if setting autonegotiation startup succesful,
+ * FALSE if starting autonegotiation failed
+ */
+uint32_t PHY_start_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, unsigned short advVal);
+
+/**
+ * This function examines, whether autonegotiation is done.
+ * Must be called after PHY_start_auto_negotiate.
+ *
+ * @param mdioBaseAddr Base Address of MDIO Module Megisters.
+ * @param phyAddr PHY Address (0-31).
+ *
+ * @return TRUE if autonegotiation succesfull and done, FALSE if autonegotiation failed.
+ */
+uint32_t PHY_is_done_auto_negotiate(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr);
+
+/**
+ * Reads the link status of the PHY.
+ *
+ * @param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * @param phyAddr PHY Address (0-31).
+ * @param retries The number of retries before indicating down status.
+ *
+ * @return link status after reading \n
+ * TRUE if link is up
+ * FALSE if link is down \n
+ *
+ * @note This reads both the basic status register of the PHY and the
+ * link register of MDIO for double check
+ **/
+uint32_t PHY_link_status_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, volatile uint32_t retries);
+
+/**
+ * Fetches RMII/MII mode of PHY.
+ *
+ * @param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * @param phyAddr PHY Address (0-31).
+ *
+ * @return TRUE if mode of PHY is set to RMII \
+ * FALSE if mode of PHY is set to MII
+ */
+uint32_t PHY_RMII_mode_get(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr);
+
+/**
+ * Sets RMII/MII mode of PHY.
+ *
+ * @param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * @param phyAddr PHY Address (0-31).
+ * @param mode Mode to set. \
+ * 1 - RMII \
+ * 0 - MII
+ */
+void PHY_MII_mode_set(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr, uint32_t mode);
+
+/**
+ * Powers down the PHY.
+ *
+ * @param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * @param phyAddr PHY Address (0-31).
+ */
+void PHY_Power_Down(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr);
+
+
+/**
+ * Powers up the PHY.
+ *
+ * @param mdioBaseAddr Base Address of the MDIO Module Registers.
+ * @param phyAddr PHY Address (0-31).
+ */
+void PHY_Power_Up(volatile tms570_mdio_t *mdioBaseAddr, uint32_t phyAddr);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __DRV_PHY_H */
diff --git a/uLan/ports/driver/tms570_emac/ti_drv_emac.h b/uLan/ports/driver/tms570_emac/ti_drv_emac.h
new file mode 100644
index 0000000..54f22c8
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/ti_drv_emac.h
@@ -0,0 +1,472 @@
+/*
+* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+/*****************************************************************************/
+#include <stdint.h>
+#include <bsp/tms570.h>
+/*
+** Macros which can be used as matchFilt parameters to the API
+** EMACMACAddrSet
+*/
+
+/*
+** Macros which can be passed as eoiFlag to EMACRxThreshIntAckToClear API
+*/
+#define EMAC_INT_CORE0_RX_THRSH (0x0u)
+#define EMAC_INT_CORE1_RX_THRSH (0x4u)
+#define EMAC_INT_CORE2_RX_THRSH (0x8u)
+
+/*
+** Macros which can be passed as eoiFlag to EMACRxIntAckToClear API
+*/
+#define EMAC_INT_CORE0_RX (0x1u)
+#define EMAC_INT_CORE1_RX (0x5u)
+#define EMAC_INT_CORE2_RX (0x9u)
+
+/*
+** Macros which can be passed as eoiFlag to EMACTxIntAckToClear API
+*/
+#define EMAC_INT_CORE0_TX (0x2u)
+#define EMAC_INT_CORE1_TX (0x6u)
+#define EMAC_INT_CORE2_TX (0xAu)
+
+/*
+** Macros which can be passed as eoiFlag to EMACMiscIntAckToClear API
+** STATPEND, HOSTPEND, MDIO LINKINT0, MDIO USERINT0
+*/
+#define EMAC_INT_CORE0_MISC (0x3u)
+#define EMAC_INT_CORE1_MISC (0x7u)
+#define EMAC_INT_CORE2_MISC (0xBu)
+
+/*****************************************************************************/
+/**
+ * \brief Enables the TXPULSE Interrupt Generation.
+ *
+ * \param emacBase Base address of the EMAC Module registers.
+ * \param emacCtrlBase Base address of the EMAC CONTROL module registers
+ * \param ctrlCore Control core for which the interrupt to be enabled.
+ * \param channel Channel number for which interrupt to be enabled
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACTxIntPulseEnable(volatile tms570_emacm_t *emacBase, volatile tms570_emacc_t *emacCtrlBase,
+ unsigned int ctrlCore, unsigned int channel)
+{
+ emacBase->TXINTMASKSET |= (1 << channel);
+ emacCtrlBase->C0TXEN |= (1 << channel);
+}
+
+/**
+ * \brief Disables the TXPULSE Interrupt Generation.
+ *
+ * \param emacBase Base address of the EMAC Module registers.
+ * \param emacCtrlBase Base address of the EMAC CONTROL module registers
+ * \param ctrlCore Control core for which the interrupt to be disabled.
+ * \param channel Channel number for which interrupt to be disabled
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACTxIntPulseDisable(volatile tms570_emacm_t *emacBase, volatile tms570_emacc_t *emacCtrlBase,
+ unsigned int ctrlCore, unsigned int channel)
+{
+ emacBase->TXINTMASKCLEAR |= (1 << channel);
+ emacCtrlBase->C0TXEN &= ~(1 << channel);
+}
+
+/**
+ * \brief Enables the RXPULSE Interrupt Generation.
+ *
+ * \param emacBase Base address of the EMAC Module registers.
+ * \param emacCtrlBase Base address of the EMAC CONTROL module registers
+ * \param ctrlCore Control core for which the interrupt to be enabled.
+ * \param channel Channel number for which interrupt to be enabled
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACRxIntPulseEnable(volatile tms570_emacm_t *emacBase, volatile tms570_emacc_t *emacCtrlBase,
+ unsigned int ctrlCore, unsigned int channel)
+{
+ emacBase->RXINTMASKSET |= (1 << channel);
+ emacCtrlBase->C0RXEN |= (1 << channel);
+}
+
+/**
+ * \brief This API enables the MII control block
+ *
+ * \param emacBase Base address of the EMAC Module registers.
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACMIIEnable(volatile tms570_emacm_t *emacBase)
+{
+ emacBase->MACCONTROL |= TMS570_EMACM_MACCONTROL_GMIIEN;
+}
+
+/**
+ * \brief This API sets the duplex mode of operation(full/half) for MAC.
+ *
+ * \param emacBase Base address of the EMAC Module registers.
+ * \param duplexMode duplex mode of operation.
+ * duplexMode can take the following values. \n
+ * nonZero - Full Duplex \n
+ * 0 - Half Duplex.
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACDuplexSet(volatile tms570_emacm_t *emacBase, int duplexMode)
+{
+ if (duplexMode) {
+ emacBase->MACCONTROL |= TMS570_EMACM_MACCONTROL_FULLDUPLEX;
+ } else {
+ emacBase->MACCONTROL &= ~TMS570_EMACM_MACCONTROL_FULLDUPLEX;
+ }
+}
+
+/**
+ * \brief API to enable the transmit in the TX Control Register
+ * After the transmit is enabled, any write to TXHDP of
+ * a channel will start transmission
+ *
+ * \param emacBase Base Address of the EMAC Module Registers.
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACTxEnable(volatile tms570_emacm_t *emacBase)
+{
+ emacBase->TXCONTROL = TMS570_EMACM_TXCONTROL_TXEN;
+}
+
+/**
+ * \brief API to enable the receive in the RX Control Register
+ * After the transmit is enabled, and write to RXHDP of
+ * a channel, the data can be received in the destination
+ * specified by the corresponding RX buffer descriptor.
+ *
+ * \param emacBase Base Address of the EMAC Module Registers.
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACRxEnable(volatile tms570_emacm_t *emacBase)
+{
+ emacBase->RXCONTROL = TMS570_EMACM_RXCONTROL_RXEN;
+}
+
+/**
+ * \brief API to write the TX HDP register. If transmit is enabled,
+ * write to the TX HDP will immediately start transmission.
+ * The data will be taken from the buffer pointer of the TX buffer
+ * descriptor written to the TX HDP
+ *
+ * \param emacBase Base Address of the EMAC Module Registers.\n
+ * \param descHdr Address of the TX buffer descriptor
+ * \param channel Channel Number
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACTxHdrDescPtrWrite(volatile tms570_emacm_t *emacBase, unsigned int descHdr,
+ unsigned int channel)
+{
+ emacBase->TXHDP[channel] = descHdr;
+}
+
+/**
+ * \brief API to write the RX HDP register. If receive is enabled,
+ * write to the RX HDP will enable data reception to point to
+ * the corresponding RX buffer descriptor's buffer pointer.
+ *
+ * \param emacBase Base Address of the EMAC Module Registers.\n
+ * \param descHdr Address of the RX buffer descriptor
+ * \param channel Channel Number
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACRxHdrDescPtrWrite(volatile tms570_emacm_t *emacBase, unsigned int descHdr,
+ unsigned int channel)
+{
+ emacBase->RXHDP[channel] = descHdr;
+}
+
+/**
+ * \brief Sets the MAC Address in MACSRCADDR registers.
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param macAddr Start address of a MAC address array.
+ * The array[0] shall be the LSB of the MAC address
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACMACSrcAddrSet(volatile tms570_emacm_t *emacBase, unsigned char *macAddr)
+{
+ emacBase->MACSRCADDRHI = macAddr[5] |(macAddr[4] << 8)
+ |(macAddr[3] << 16) |(macAddr[2] << 24);
+ emacBase->MACSRCADDRLO = macAddr[1] | (macAddr[0] << 8);
+}
+
+/**
+ * \brief Sets the MAC Address in MACADDR registers.
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param channel Channel Number
+ * \param matchFilt Match or Filter
+ * \param macAddr Start address of a MAC address array.
+ * The array[0] shall be the LSB of the MAC address
+ * matchFilt can take the following values \n
+ * EMAC_MACADDR_NO_MATCH_NO_FILTER - Address is not used to match
+ * or filter incoming packet. \n
+ * EMAC_MACADDR_FILTER - Address is used to filter incoming packets \n
+ * EMAC_MACADDR_MATCH - Address is used to match incoming packets \n
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACMACAddrSet(volatile tms570_emacm_t *emacBase, unsigned int channel,
+ unsigned char *macAddr, unsigned int matchFilt)
+{
+ emacBase->MACINDEX = channel;
+
+ emacBase->MACADDRHI = macAddr[5] |(macAddr[4] << 8)
+ |(macAddr[3] << 16) |(macAddr[2] << 24);
+ emacBase->MACADDRLO = macAddr[1] | (macAddr[0] << 8)
+ | matchFilt | (channel << 16);
+}
+
+/**
+ * \brief Acknowledges an interrupt processed to the EMAC Control Core.
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param eoiFlag Type of interrupt to acknowledge to the EMAC Control
+ * module.
+ * eoiFlag can take the following values \n
+ * EMAC_INT_CORE0_TX - Core 0 TX Interrupt
+ * EMAC_INT_CORE1_TX - Core 1 TX Interrupt
+ * EMAC_INT_CORE2_TX - Core 2 TX Interrupt
+ * EMAC_INT_CORE0_RX - Core 0 RX Interrupt
+ * EMAC_INT_CORE1_RX - Core 1 RX Interrupt
+ * EMAC_INT_CORE2_RX - Core 2 RX Interrupt
+ * \return None
+ *
+ **/
+static inline void
+EMACCoreIntAck(volatile tms570_emacm_t *emacBase, unsigned int eoiFlag)
+{
+ /* Acknowledge the EMAC Control Core */
+ emacBase->MACEOIVECTOR = eoiFlag;
+}
+
+/**
+ * \brief Writes the the RX Completion Pointer for a specific channel
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param channel Channel Number.
+ * \param comPtr Completion Pointer Value to be written
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACRxCPWrite(volatile tms570_emacm_t *emacBase, unsigned int channel, unsigned int comPtr)
+{
+ emacBase->RXCP[channel] = comPtr;
+}
+
+/**
+ * \brief Acknowledges an interrupt processed to the EMAC module. After
+ * processing an interrupt, the last processed buffer descriptor is
+ * written to the completion pointer. Also this API acknowledges
+ * the EMAC Control Module that the RX interrupt is processed for
+ * a specified core
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param channel Channel Number
+ * \param comPtr Completion Pointer value. This shall be the buffer
+ * descriptor address last processed.
+ * \param eoiFlag Type of interrupt to acknowledge to the EMAC Control
+ module.
+ * eoiFlag can take the following values \n
+ * EMAC_INT_CORE0_RX - Core 0 RX Interrupt
+ * EMAC_INT_CORE1_RX - Core 1 RX Interrupt
+ * EMAC_INT_CORE2_RX - Core 2 RX Interrupt
+ * \return None
+ *
+ **/
+static inline void
+EMACRxIntAckToClear(volatile tms570_emacm_t *emacBase, unsigned int channel,
+ unsigned int comPtr, unsigned eoiFlag)
+{
+ emacBase->RXCP[channel] = comPtr;
+
+ /* Acknowledge the EMAC Control Core */
+ emacBase->MACEOIVECTOR = eoiFlag;
+}
+
+/**
+ * \brief Enables a specific channel to receive broadcast frames
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param channel Channel Number.
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACRxBroadCastEnable(volatile tms570_emacm_t *emacBase, unsigned int channel)
+{
+ emacBase->RXMBPENABLE &= ~TMS570_EMACM_RXMBPENABLE_RXBROADCH(-1); //CHECK
+
+ emacBase->RXMBPENABLE |=
+ TMS570_EMACM_RXMBPENABLE_RXBROADEN |
+ TMS570_EMACM_RXMBPENABLE_RXBROADCH(channel);
+}
+
+static inline void
+EMACRxPromiscEnable(volatile tms570_emacm_t *emacBase, unsigned int channel)
+{
+ emacBase->RXMBPENABLE |= TMS570_EMACM_RXMBPENABLE_RXCAFEN | TMS570_EMACM_RXMBPENABLE_RXCEFEN;
+ emacBase->RXMBPENABLE |= TMS570_EMACM_RXMBPENABLE_RXPROMCH(channel);
+}
+/**
+ * \brief Enables unicast for a specific channel
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param channel Channel Number.
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACRxUnicastSet(volatile tms570_emacm_t *emacBase, unsigned int channel)
+{
+ emacBase->RXUNICASTSET |= (1 << channel);
+}
+
+
+/**
+ * \brief Gets the interrupt vectors of EMAC, which are pending
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ *
+ * \return Vectors
+ *
+ **/
+static inline unsigned int
+EMACIntVectorGet(volatile tms570_emacm_t *emacBase)
+{
+ return (emacBase->MACINVECTOR);
+}
+
+/**
+ * \brief Writes the the TX Completion Pointer for a specific channel
+ *
+ * \param emacBase Base Address of the EMAC module registers.
+ * \param channel Channel Number.
+ * \param comPtr Completion Pointer Value to be written
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACTxCPWrite(volatile tms570_emacm_t *emacBase, unsigned int channel, unsigned int comPtr)
+{
+ emacBase->TXCP[channel] = comPtr;
+}
+
+/**
+ * \brief This API Initializes the EMAC and EMAC Control modules. The
+ * EMAC Control module is reset, the CPPI RAM is cleared. also,
+ * all the interrupts are disabled. This API doesnot enable any
+ * interrupt or operation of the EMAC.
+ *
+ * \param emacCtrlBase Base Address of the EMAC Control module
+ * registers.\n
+ * \param emacBase Base address of the EMAC module registers
+ *
+ * \return None
+ *
+ **/
+static inline void
+EMACInit(volatile tms570_emacc_t *emacCtrlBase, volatile tms570_emacm_t *emacBase)
+{
+ unsigned int cnt;
+
+ /* Reset the EMAC Control Module. This clears the CPPI RAM also */
+ emacCtrlBase->SOFTRESET = TMS570_EMACC_SOFTRESET_RESET;
+ while (emacCtrlBase->SOFTRESET & TMS570_EMACC_SOFTRESET_RESET);
+
+ /* Reset the EMAC Control Module. This clears the CPPI RAM also */
+ emacBase->SOFTRESET = TMS570_EMACM_SOFTRESET_SOFTRESET;
+
+ while (emacBase->SOFTRESET & TMS570_EMACM_SOFTRESET_SOFTRESET);
+
+ emacBase->MACCONTROL = 0;
+ emacBase->RXCONTROL = 0;
+ emacBase->TXCONTROL = 0;
+
+ /* Initialize all the header descriptor pointer registers */
+ for (cnt = 0; cnt < sizeof(emacBase->RXHDP)/sizeof(emacBase->RXHDP[0]); cnt++) { //CHECK
+ emacBase->RXHDP[cnt] = 0;
+ emacBase->TXHDP[cnt] = 0;
+ emacBase->RXCP[cnt] = 0;
+ emacBase->TXCP[cnt] = 0;
+ emacBase->RXFREEBUFFER[cnt] = 0xFF;
+ }
+ /* Clear the interrupt enable for all the channels */
+ emacBase->TXINTMASKCLEAR = 0xFF;
+ emacBase->RXINTMASKCLEAR = 0xFF;
+
+ emacBase->MACHASH1 = 0;
+ emacBase->MACHASH2 = 0;
+
+ emacBase->RXBUFFEROFFSET = 0;
+}
diff --git a/uLan/ports/driver/tms570_emac/ti_drv_mdio.h b/uLan/ports/driver/tms570_emac/ti_drv_mdio.h
new file mode 100644
index 0000000..e115231
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/ti_drv_mdio.h
@@ -0,0 +1,165 @@
+/*
+* Copyright (C) 2009-2015 Texas Instruments Incorporated - www.ti.com
+*
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+*
+* Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the
+* distribution.
+*
+* Neither the name of Texas Instruments Incorporated nor the names of
+* its contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#ifndef __MDIO_H__
+#define __MDIO_H__
+
+#include <bsp/tms570.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*****************************************************************************/
+/**
+ * \brief Reads a PHY register using MDIO.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param regNum Register Number to be read.
+ * \param dataPtr Pointer where the read value shall be written.
+ *
+ * \return status of the read \n
+ * TRUE - read is successful.\n
+ * FALSE - read is not acknowledged properly.
+ *
+ **/
+
+static inline uint32_t
+MDIOPhyRegRead(volatile tms570_mdio_t *baseAddr, uint32_t phyAddr,
+ uint32_t regNum, volatile unsigned short *dataPtr)
+{
+ /* Wait till transaction completion if any */
+ while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO);
+
+ baseAddr->USERACCESS0
+ = (TMS570_MDIO_USERACCESS0_GO
+ |TMS570_MDIO_USERACCESS0_REGADR(regNum)
+ |TMS570_MDIO_USERACCESS0_PHYADR(phyAddr));
+
+ /* wait for command completion */
+ while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO);
+
+ /* Store the data if the read is acknowledged */
+ if (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_ACK) {
+ *dataPtr = (unsigned short)TMS570_MDIO_USERACCESS0_DATA_GET(baseAddr->USERACCESS0);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * \brief Writes a PHY register using MDIO.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param phyAddr PHY Adress.
+ * \param regNum Register Number to be read.
+ * \param RegVal Value to be written.
+ *
+ * \return None
+ *
+ **/
+static inline void
+MDIOPhyRegWrite(volatile tms570_mdio_t *baseAddr, uint32_t phyAddr,
+ uint32_t regNum, unsigned short RegVal)
+{
+ /* Wait till transaction completion if any */
+ while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO);
+
+ baseAddr->USERACCESS0 =
+ (TMS570_MDIO_USERACCESS0_WRITE
+ | TMS570_MDIO_USERACCESS0_GO
+ |TMS570_MDIO_USERACCESS0_REGADR(regNum)
+ |TMS570_MDIO_USERACCESS0_PHYADR(phyAddr)
+ | RegVal);
+
+ /* wait for command completion*/
+ while (baseAddr->USERACCESS0 & TMS570_MDIO_USERACCESS0_GO);
+}
+/**
+ * \brief Reads the alive status of all PHY connected to this MDIO.
+ * The bit correponding to the PHY address will be set if the PHY
+ * is alive.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ *
+ * \return MDIO alive register state
+ *
+ **/
+static inline uint32_t
+MDIOPhyAliveStatusGet(volatile tms570_mdio_t *baseAddr)
+{
+ return (baseAddr->ALIVE);
+}
+
+/**
+ * \brief Reads the link status of all PHY connected to this MDIO.
+ * The bit correponding to the PHY address will be set if the PHY
+ * link is active.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ *
+ * \return MDIO link register state
+ *
+ **/
+static inline uint32_t
+MDIOPhyLinkStatusGet(volatile tms570_mdio_t *baseAddr)
+{
+ return (baseAddr->LINK);
+}
+
+/**
+ * \brief Initializes the MDIO peripheral. This enables the MDIO state
+ * machine, uses standard pre-amble and set the clock divider value.
+ *
+ * \param baseAddr Base Address of the MDIO Module Registers.
+ * \param mdioInputFreq The clock input to the MDIO module
+ * \param mdioOutputFreq The clock output required on the MDIO bus
+ * \return None
+ *
+ **/
+static inline void
+MDIOInit(volatile tms570_mdio_t *baseAddr, uint32_t mdioInputFreq,
+ uint32_t mdioOutputFreq)
+{
+ baseAddr->CONTROL = TMS570_MDIO_CONTROL_HIGHEST_USER_CHANNEL(1) |
+ TMS570_MDIO_CONTROL_ENABLE |
+ TMS570_MDIO_CONTROL_CLKDIV(0x60);
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MDIO_H__ */
diff --git a/uLan/ports/driver/tms570_emac/tms570_emac.h b/uLan/ports/driver/tms570_emac/tms570_emac.h
new file mode 100644
index 0000000..26993e9
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/tms570_emac.h
@@ -0,0 +1,117 @@
+#ifndef EMAC_H_
+#define EMAC_H_
+
+#include <stdbool.h>
+#include "netif/etharp.h"
+#include "lwip/sys.h"
+#include "bsp/tms570.h"
+
+/*to rtems*/
+#define EMAC_CTRL_RAM_BASE (0xFC520000U)
+#define SIZE_EMAC_CTRL_RAM 0x2000U
+
+
+
+
+/* Packet Flags EMAC_Desc - tx and rx */
+#define EMAC_DSC_FLAG_SOP 0x80000000u
+#define EMAC_DSC_FLAG_EOP 0x40000000u
+#define EMAC_DSC_FLAG_OWNER 0x20000000u
+#define EMAC_DSC_FLAG_EOQ 0x10000000u
+#define EMAC_DSC_FLAG_TDOWNCMPLT 0x08000000u
+#define EMAC_DSC_FLAG_PASSCRC 0x04000000u
+/* Packet Flags - in addition to rx */
+#define EMAC_DSC_FLAG_JABBER 0x02000000u
+#define EMAC_DSC_FLAG_OVERSIZE 0x01000000u
+#define EMAC_DSC_FLAG_FRAGMENT 0x00800000u
+#define EMAC_DSC_FLAG_UNDERSIZED 0x00400000u
+#define EMAC_DSC_FLAG_CONTROL 0x00200000u
+#define EMAC_DSC_FLAG_OVERRUN 0x00100000u
+#define EMAC_DSC_FLAG_CODEERROR 0x00080000u
+#define EMAC_DSC_FLAG_ALIGNERROR 0x00040000u
+#define EMAC_DSC_FLAG_CRCERROR 0x00020000u
+#define EMAC_DSC_FLAG_NOMATCH 0x00010000u
+
+/********** TI structs ***********/
+
+/* EMAC TX Buffer descriptor data structure */
+struct emac_tx_bd {
+ volatile struct emac_tx_bd *next;
+ volatile u8_t *bufptr;
+ volatile u32_t bufoff_len;
+ volatile u32_t flags_pktlen;
+
+ /* helper to know which pbuf this tx bd corresponds to */
+ struct pbuf *pbuf;
+};
+
+/* EMAC RX Buffer descriptor data structure */
+struct emac_rx_bd {
+ volatile struct emac_rx_bd *next;
+ volatile u8_t *bufptr;
+ volatile u32_t bufoff_len;
+ volatile u32_t flags_pktlen;
+
+ /* helper to know which pbuf this rx bd corresponds to */
+ struct pbuf *pbuf;
+};
+
+/**
+ * Helper struct to hold the data used to operate on a particular
+ * receive channel
+ */
+struct rxch{
+ volatile struct emac_rx_bd *active_head;
+ volatile struct emac_rx_bd *active_tail;
+ volatile struct emac_rx_bd *inactive_head;
+ volatile struct emac_rx_bd *inactive_tail;
+ s32_t freed_pbuf_len;
+};
+
+/**
+ * Helper struct to hold the data used to operate on a particular
+ * transmit channel
+ */
+struct txch {
+ volatile struct emac_tx_bd *active_head;
+ volatile struct emac_tx_bd *active_tail;
+ volatile struct emac_tx_bd *inactive_head;
+ volatile struct emac_tx_bd *inactive_tail;
+};
+
+/**
+ * Helper struct to hold private data used to operate the ethernet interface.
+ */
+struct tms570_netif_state {
+ /* emac instance number */
+ u32_t inst_num;
+
+ /* EMAC configuration register-window base address */
+ volatile tms570_emacm_t *emac_base;
+
+ /* EMAC controller base address */
+ volatile tms570_emacc_t *emac_ctrl_base;
+ volatile u32_t emac_ctrl_ram;
+
+ /* MDIO base address */
+ volatile tms570_mdio_t *mdio_base;
+
+ /* The RX/TX channel 0 state description
+ * (keeps track of used/freed Buffer Descriptors)
+ */
+ struct txch txch;
+ struct rxch rxch;
+
+ /* Semaphores used for waking up the threads processing
+ * RX/TX packets in teh deferred manner.
+ * Semgive is called in particular RX/TX interrupt
+ */
+ sys_sem_t intPend_sem;
+
+ u32_t phy_addr;
+ uint32_t waitTicksForPHYAneg;
+};
+
+/********************************************** End of Statistics **********************************************/
+
+#endif /* EMAC_H_ */
diff --git a/uLan/ports/driver/tms570_emac/tms570_netif.c b/uLan/ports/driver/tms570_emac/tms570_netif.c
new file mode 100644
index 0000000..8d14687
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/tms570_netif.c
@@ -0,0 +1,1227 @@
+/*
+ * Copyright (c) 2013, 2015 Czech Technical University in Prague
+ * Czech Republic
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Premysl Houdek <houdepre@fel.cvut.cz>
+ * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Industrial Informatics Group, FEE, Czech Technical University in Prague
+ *
+ * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal
+ */
+
+/* lwIP headers */
+#include "lwip/init.h"
+#if LWIP_VERSION_MAJOR >= 2
+#include "lwip/timeouts.h"
+#else /*LWIP_VERSION_MAJOR*/
+#include "lwip/timers.h" /* for DHCP binding in NO_SYS mode */
+#endif /*LWIP_VERSION_MAJOR*/
+#include "lwip/sys.h" /* includes - lwip/opt.h, lwip/err.h, arch/sys_arch.h */
+#include "lwip/tcpip.h" /* includes - lwip/opt.h, lwip/api_msg.h, lwip/netifapi.h, lwip/pbuf.h, lwip/api.h, lwip/sys.h, lwip/timers.h, lwip/netif.h */
+#include "lwip/stats.h" /* includes - lwip/mem.h, lwip/memp.h, lwip/opt.h */
+#include "lwip/snmp.h"
+#include "netif/etharp.h" /* includes - lwip/ip.h, lwip/netif.h, lwip/ip_addr.h, lwip/pbuf.h */
+#include <lwip/netifapi.h>
+/* end - lwIP headers */
+
+//--------moje
+#include <strings.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <bsp/irq.h>
+#include <bsp/tms570.h>
+#include <bsp/tms570-pinmux.h>
+#include "arch/cc.h"
+#include "eth_lwip.h"
+#include "tms570_netif.h"
+#include "ti_drv_emac.h"
+#include "ti_drv_mdio.h"
+#include "phy_dp83848h.h"
+#include "tms570_emac.h"
+
+#define LINK_SPEED_OF_YOUR_NETIF_IN_BPS 10000000
+
+/* Number of EMAC Instances */
+
+#define DEFAULT_PHY_ADDR 0x1
+#define FIND_FIRST_PHY_ALIVE 1 /* or use default (phy_address: 1) */
+#define NUM_OF_PHYs 32
+
+/* Size of the Buffer descriptor defined by the EMAC in bytes */
+#define SIZE_OF_DESC 16
+
+/* Channel number used for for RX, TX, unicast, broadcast or damaged frames;
+ * there are different channels for rx and tx operations (i.e. RXCH0 != TXCH0) */
+#define CHANNEL 0
+
+/* take in account oversized frames */
+#define MAX_TRANSFER_UNIT 1500
+
+#ifndef TMS570_MMR_SELECT_GMII_SEL
+ #define TMS570_MMR_SELECT_GMII_SEL TMS570_BALL_XX_GMII_SEL
+#endif
+
+#ifndef TMS570_BALL_K19_MII_RXCLK
+ #define TMS570_BALL_K19_MII_RXCLK TMS570_BALL_K19_MII_RX_CLK
+#endif
+
+/* WARNING!
+ * Be very carefull when setting this value. We have to keep in mind
+ * that pbuf_alloc(..., PBUF_POOL) will usualy return a chain of PBUFs
+ * pointing to the statically preallocated buffers (of the same size).
+ * The problem is that if we ask to allocate 300 bytes whereby the size
+ * of the statically preallocated PBUFs (PBUF_POOL_BUFSIZE) is 256, we
+ * will get a chain containing two PBUFs -- one *reporting* its size to
+ * be 256 bytes, the other one 44 bytes.
+ * Everything seems to be just fine however during RX, after we call
+ * netif->input(pbuf, netif) we have to newly allocate the PBUF(s) and
+ * properly set the apropriate BDs. This will however work only if the
+ * number of the freed BDs is the same as the number of the BDs newly
+ * initialized. One possible situation when this may fail is when multiple
+ * non-256 byte sized PBUFs will move near to each other, i.e. 3 BDs:
+ * 256 B, 44 B, 44 B -- 344 bytes will be freed (3 BDs) but the new call
+ * to pbuf_alloc(...) will return a chain comprising only two PBUFs
+ * (256 B, 88 B).
+ * This is the implementation limitation. The PBUF_LEN_MAX should therefore
+ * be multiple of PBUF_POOL_BUFSIZE
+ */
+#define PBUF_LEN_MAX (PBUF_POOL_BUFSIZE * 6)
+
+/* Maximum number of PBUFs preallocated in the driver
+ * init function to be used for the RX
+ */
+#define MAX_RX_PBUF_ALLOC 10
+#define MIN_PKT_LEN 60
+
+/* Define those to better describe the network interface. */
+#define IFNAME0 'e'
+#define IFNAME1 'n'
+
+/* Time to wait for autonegotiation in ticks. */
+#define TICKS_PHY_AUTONEG 4000
+
+/* startup init indicator */
+static bool initialized = false;
+
+/*private?*/
+#if !defined(__TI_COMPILER_VERSION__)
+static
+#endif /*__TI_COMPILER_VERSION__*/
+SYS_IRQ_HANDLER_FNC(tms570_eth_irq);
+static void tms570_eth_rx_pbuf_refill(struct tms570_netif_state *nf_state, int);
+static void tms570_eth_rx_pbuf_refill_single(struct netif *);
+static void tms570_eth_hw_set_RX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_rx_bd *new_head);
+static void tms570_eth_hw_set_TX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_tx_bd *new_head);
+static void tms570_eth_hw_set_hwaddr(struct tms570_netif_state *nf_state, uint8_t *mac_addr);
+static void tms570_eth_process_irq_rx(void *arg);
+static void tms570_eth_process_irq_tx(void *arg);
+static void tms570_eth_process_irq_request(void *argument);
+static void tms570_eth_process_irq(void *argument);
+struct netif *tms570_eth_get_netif(uint32_t instance_number);
+static err_t tms570_eth_send(struct netif *netif, struct pbuf *p);
+static err_t tms570_eth_send_raw(struct netif *netif, struct pbuf *pbuf);
+static err_t tms570_eth_init_hw(struct tms570_netif_state *nf_state);
+static err_t tms570_eth_init_hw_post_init(struct tms570_netif_state *nf_state);
+static err_t tms570_eth_init_interrupt(struct tms570_netif_state *nf_state);
+static err_t tms570_eth_init_find_PHY(struct tms570_netif_state *nf_state);
+static err_t tms570_eth_init_control_structures(struct netif *netif);
+static void tms570_eth_init_netif_fill(struct netif *netif);
+static void tms570_eth_init_buffer_descriptors(struct tms570_netif_state *nf_state);
+static void tms570_eth_init_set_pinmux();
+
+/***** initializing functions **********************************************/
+
+
+struct tms570_netif_state *
+tms570_eth_init_state(void)
+{
+ struct tms570_netif_state *nf_state = (struct tms570_netif_state *)malloc(sizeof(struct tms570_netif_state));
+
+ nf_state->emac_base = &TMS570_EMACM;
+ nf_state->emac_ctrl_base = &TMS570_EMACC;
+ nf_state->emac_ctrl_ram = EMAC_CTRL_RAM_BASE;
+ nf_state->mdio_base = &TMS570_MDIO;
+ nf_state->phy_addr = DEFAULT_PHY_ADDR;
+#if !NO_SYS
+ nf_state->waitTicksForPHYAneg = TICKS_PHY_AUTONEG;
+#endif
+ return nf_state;
+}
+
+static void
+tms570_eth_init_netif_fill(struct netif *netif)
+{
+#if LWIP_NETIF_HOSTNAME
+ netif->hostname = "tms570";
+#endif
+
+ netif->name[0] = IFNAME0;
+ netif->name[1] = IFNAME1;
+
+ /*
+ * Initialize the snmp variables and counters inside the struct netif.
+ * The last argument should be replaced with your link speed, in units
+ * of bits per second.
+ */
+ NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
+
+ /* We directly use etharp_output() here to save a function call.
+ * You can instead declare yo_SKIP_TO_HWur own function an call etharp_output()
+ * from it if you have to do some checks before sending (e.g. if link
+ * is available...)
+ */
+ netif->output = etharp_output;
+ netif->linkoutput = tms570_eth_send;
+
+ /* maximum transfer unit */
+ netif->mtu = MAX_TRANSFER_UNIT;
+
+ /* device capabilities */
+ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
+ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
+}
+
+static err_t
+tms570_eth_init_control_structures(struct netif *netif)
+{
+ err_t res;
+ sys_thread_t tx_thread_id;
+ struct tms570_netif_state *nf_state;
+
+ nf_state = netif->state;
+
+ res = sys_sem_new(&nf_state->intPend_sem, 0);
+ if (res != ERR_OK) {
+ sys_arch_printk("ERROR! semaphore creation error - 0x%08lx\n", (long)res);
+ }
+ tx_thread_id = sys_thread_new(0, tms570_eth_process_irq_request, netif, 1024, 3); //zkontrolovat priorita 0
+ if (tx_thread_id == 0) {
+ sys_arch_printk("ERROR! lwip interrupt thread not created");
+ res = !ERR_OK;
+ }
+ return res;
+}
+
+err_t
+tms570_eth_init_netif(struct netif *netif)
+{
+ err_t retVal;
+ struct tms570_netif_state *nf_state = (struct tms570_netif_state *)netif->state;
+
+ if (initialized)
+ return ERR_IF;
+
+ if (nf_state == NULL) {
+ /* nf_state needs to be freed */
+ if ((nf_state = tms570_eth_init_state()) == 0) {
+ return ERR_IF;
+ }
+ netif->state = nf_state;
+ }
+
+ tms570_eth_init_netif_fill(netif);
+
+ if ((retVal = tms570_eth_init_hw(nf_state)) != ERR_OK) {
+ tms570_eth_debug_printf("tms570_eth_init_hw: %d", retVal);
+ return retVal;
+ }
+ if ((retVal = tms570_eth_init_control_structures(netif)) != ERR_OK) {
+ tms570_eth_debug_printf("tms570_eth_init_control_structures: %d", retVal);
+ return retVal;
+ }
+ tms570_eth_init_buffer_descriptors(nf_state);
+ tms570_eth_rx_pbuf_refill(nf_state, 0);
+ tms570_eth_hw_set_hwaddr(nf_state, netif->hwaddr);
+ tms570_eth_init_interrupt(nf_state);
+ if ((retVal = tms570_eth_init_hw_post_init(nf_state)) != ERR_OK) {
+ tms570_eth_debug_printf("tms570_eth_init_hw_post_init: %d", retVal);
+ return retVal;
+ }
+ initialized = true;
+#if TMS570_NETIF_DEBUG
+ tms570_eth_debug_print_HDP(nf_state);
+#endif
+ return ERR_OK;
+}
+
+static err_t
+tms570_eth_init_interrupt(struct tms570_netif_state *nf_state)
+{
+ int res;
+
+ res = sys_request_irq(TMS570_IRQ_EMAC_TX, tms570_eth_irq,
+ 0, "emac_tx", nf_state);
+ if (res < 0) {
+ sys_arch_printk("Failed to install tx handler\n");
+ return ERR_IF;
+ }
+
+ res = sys_request_irq(TMS570_IRQ_EMAC_RX, tms570_eth_irq,
+ 0, "emac_rx", nf_state);
+ if (res < 0) {
+ sys_arch_printk("Failed to install rx handler\n");
+ return ERR_IF;
+ }
+ return ERR_OK;
+}
+static err_t
+tms570_eth_init_find_PHY(struct tms570_netif_state *nf_state)
+{
+ uint8_t index;
+ uint16_t regContent;
+ uint32_t physAlive;
+
+ MDIOPhyRegRead(nf_state->mdio_base, nf_state->phy_addr, PHY_BMSR, &regContent);
+ physAlive = MDIOPhyAliveStatusGet(nf_state->mdio_base);
+ /* Find first alive PHY -- or use default if alive */
+ if (!(physAlive & (1 << nf_state->phy_addr))) {
+ for (index = 0; index < NUM_OF_PHYs; index++) {
+ if (physAlive & (1 << index)) {
+ nf_state->phy_addr = index;
+ break;
+ } else {
+ /*
+ * Try to 'wake up' PHY on 'index' address by
+ * reading random register, making MDIO set
+ * alive bit for current PHY
+ */
+ MDIOPhyRegRead(nf_state->mdio_base, index,
+ PHY_BMCR, &regContent);
+
+ /* Get updated register */
+ physAlive = MDIOPhyAliveStatusGet(nf_state->mdio_base);
+ if (physAlive & (1 << index)) {
+ nf_state->phy_addr = index;
+ break;
+ }
+ }
+ }
+
+ if (!physAlive) { /* FIXME je to ok? */
+ tms570_eth_debug_printf("no phy found, phys: %d\n", physAlive);
+ return NO_PHY_ALIVE;
+ }
+ }
+ return ERR_OK;
+}
+
+static void
+tms570_eth_init_set_pinmux(void)
+{
+#if defined(__rtems__)
+ TMS570_IOMM.KICK_REG0 = 0x83E70B13U;
+ TMS570_IOMM.KICK_REG1 = 0x95A4F1E0U;
+
+ tms570_bsp_pin_set_function(TMS570_BALL_V5_MDCLK, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_G3_MDIO, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_H19_MII_TXEN, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_E18_MII_TXD_3, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_R2_MII_TXD_2, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_J19_MII_TXD_1, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_J18_MII_TXD_0, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_D19_MII_TX_CLK, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_H18_MII_RXD_3, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_G19_MII_RXD_2, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_A14_MII_RXD_1, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_P1_MII_RXD_0, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_K19_MII_RXCLK, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_N19_MII_RX_ER, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_B11_MII_RX_DV, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_B4_MII_CRS, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_set_function(TMS570_BALL_F3_MII_COL, TMS570_PIN_FNC_AUTO);
+ tms570_bsp_pin_clear_function(TMS570_MMR_SELECT_GMII_SEL, TMS570_PIN_FNC_AUTO);
+
+ TMS570_IOMM.KICK_REG0 = 0;
+ TMS570_IOMM.KICK_REG1 = 0;
+#endif /*__rtems__*/
+}
+
+static err_t
+tms570_eth_init_hw(struct tms570_netif_state *nf_state)
+{
+ err_t retVal;
+
+ tms570_eth_init_set_pinmux();
+
+ /* Initialize EMAC control module and EMAC module */
+ EMACInit(nf_state->emac_ctrl_base, nf_state->emac_base);
+ /* Initialize MDIO module (reset) */
+ MDIOInit(nf_state->mdio_base, 0x0, 0x0);
+
+ if ((retVal = tms570_eth_init_find_PHY(nf_state)) != ERR_OK) {
+ tms570_eth_debug_printf("tms570_eth_init_find_PHY: %d", retVal);
+ return retVal;
+ }
+ /*
+ * Start autonegotiation and check on completion later or
+ * when complete link register will be updated
+ */
+ PHY_auto_negotiate(nf_state->mdio_base, nf_state->phy_addr,
+ PHY_100BASETXDUPL_m | PHY_100BASETX_m |
+ PHY_10BASETDUPL_m | PHY_10BASET_m);
+ tms570_eth_debug_printf("autoneg started -- check on cable if it's connected!\r\n");
+
+ /*
+ * TODO: you can implement init of receive flow control somewhere
+ * here if desired - set RXBUFFERFLOWEN in MACCONTROL
+ */
+
+ /* Acknowledge EMAC control module RX, TX and MISC interrupts */
+ EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_RX);
+ EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_TX);
+ EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_MISC);
+
+ /* Sets which channel will receive broadcasts */
+ EMACRxBroadCastEnable(nf_state->emac_base, CHANNEL);
+
+ /*
+ * Sets channel where all frames will be copied to --
+ * either with MAC address different from local device address,
+ * either packets with error will be copied; appropriate error
+ * will be set in the frame EOP buffer descriptor
+ */
+ EMACRxPromiscEnable(nf_state->emac_base, CHANNEL);
+
+ /* Enable unicast */
+ EMACRxUnicastSet(nf_state->emac_base, CHANNEL);
+
+ /* Enable TX and RX interrupts in both EMAC module and EMAC control module */
+ EMACTxIntPulseEnable(nf_state->emac_base, nf_state->emac_ctrl_base, 0, CHANNEL);
+ EMACRxIntPulseEnable(nf_state->emac_base, nf_state->emac_ctrl_base, 0, CHANNEL);
+
+ return ERR_OK;
+}
+static void
+tms570_eth_hw_set_hwaddr(struct tms570_netif_state *nf_state, uint8_t *mac_addr)
+{
+ uint8_t mac[ETHARP_HWADDR_LEN];
+ int i;
+
+ for (i = 0; i < ETHARP_HWADDR_LEN; i++) {
+ mac[i] = mac_addr[ETHARP_HWADDR_LEN - i - 1];
+ }
+ /* for flow control frames */
+ EMACMACSrcAddrSet(nf_state->emac_base, mac);
+
+ /* Be sure to program all eight MAC address registers -
+ * whether the receive channel is to be enabled or not.
+ */
+ for (i = 0; i < 8; i++) {
+ EMACMACAddrSet(nf_state->emac_base, i, mac, 0);
+ }
+}
+
+static err_t
+tms570_eth_init_hw_post_init(struct tms570_netif_state *nf_state)
+{
+ /* 0x3FFFFFFF is for 80MHz aproximately 13s */
+ uint16_t regContent;
+
+ /* wait for autonegotiation to be done or continue, when delay was reached */
+ uint32_t timeToWake = nf_state->waitTicksForPHYAneg + sys_jiffies();
+
+ while (PHY_is_done_auto_negotiate(nf_state->mdio_base, nf_state->phy_addr) == false &&
+ timeToWake > sys_jiffies())
+ sys_arch_delay(20);
+ /* XXX: if init is not done at the startup,
+ * but couple days later, this might cause troubles */
+
+ if (PHY_is_done_auto_negotiate(nf_state->mdio_base, nf_state->phy_addr) != false)
+ tms570_eth_debug_printf("autoneg finished\n");
+ else
+ tms570_eth_debug_printf("autoneg timeout\n");
+
+ /* provide informations retrieved from autoneg to EMAC module */
+ PHY_partner_ability_get(nf_state->mdio_base, nf_state->phy_addr, &regContent);
+ if (regContent & (PHY_100BASETXDUPL_m | PHY_10BASETDUPL_m)) {
+ EMACDuplexSet(nf_state->emac_base, 1);
+ /* this is right place to implement transmit flow control if desired --
+ * set TXFLOWEN in MACCONTROL
+ */
+ } else if (regContent & (PHY_100BASETX_m | PHY_10BASET_m)) {
+ EMACDuplexSet(nf_state->emac_base, 0);
+ } else {
+ tms570_eth_debug_printf("Unknown duplex mode\r\n");
+ return UNKN_DUPLEX_MODE;
+ }
+
+ /* enable hostpend interrupts in emac module */
+ nf_state->emac_base->MACINTMASKSET |= TMS570_EMACM_MACINTMASKSET_HOSTMASK;
+
+ /* enable hostpend interrupts in emac control module */
+ nf_state->emac_ctrl_base->C0MISCEN |= TMS570_EMACC_C0MISCEN_HOSTPENDEN;
+
+ EMACMIIEnable(nf_state->emac_base);
+ EMACTxEnable(nf_state->emac_base);
+ EMACRxEnable(nf_state->emac_base);
+
+ return ERR_OK;
+}
+static void
+tms570_eth_init_buffer_descriptors(struct tms570_netif_state *nf_state)
+{
+ uint32_t num_bd;
+ volatile struct emac_tx_bd *curr_txbd;
+ volatile struct emac_rx_bd *curr_rxbd;
+
+ struct rxch *rxch;
+ struct txch *txch;
+
+ rxch = &(nf_state->rxch);
+ txch = &(nf_state->txch);
+
+
+ /*
+ * Use the CPPI RAM to store RX/TX Buffer Descriptors (= BD).
+ * 1/2 of CPPI RAM is used for TX BDs, another 1/2 for RX BDs.
+ * All the TX BDs are 'owned' by the software. They are initialized
+ * as a linked-list forming a ring. They are awaiting the application
+ * to append pbuf payload to the them and correctly configure for
+ * actual transmission.
+ * Only such number of RX BDs is configured that the pbufs can be
+ * allocated for (i.e. MAX_RX_PBUF_ALLOC). Pbufs are allocated from
+ * the PBUF_POOL (thus the allocated pbufs might be chained).
+ * Each payload part of a payload is them used to initialize single
+ * RX BD. The RX BDs are then configured to be 'owned' bythe EMAC
+ */
+
+ /*
+ * Initialize the Descriptor Memory For TX and RX
+ * Only Channel 0 is supported for both TX and RX
+ */
+ txch->inactive_head = (volatile struct emac_tx_bd *)nf_state->emac_ctrl_ram;
+ txch->inactive_tail = NULL;
+ txch->active_head = NULL;
+ txch->active_tail = NULL;
+
+ /* Set the number of descriptors for the channel */
+ /* take half of CPPI ram for TX BDs */
+
+ num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_tx_bd))-1;
+#if TMS570_NETIF_DEBUG
+ tms570_eth_debug_printf("pocet bd %d\n", num_bd);
+#endif
+
+ curr_txbd = txch->inactive_head;
+
+ /* Initialize all the TX buffer Descriptors */
+ while (num_bd > 0) {
+ curr_txbd->next = curr_txbd + 1;
+ curr_txbd->flags_pktlen = 0;
+ txch->inactive_tail = curr_txbd;
+ curr_txbd = curr_txbd->next;
+ num_bd--;
+ }
+ curr_txbd->next = NULL;
+
+ /* Initialize the descriptors for the RX channel */
+ rxch->inactive_head = ((volatile struct emac_rx_bd *)curr_txbd)+2;
+ rxch->freed_pbuf_len = MAX_RX_PBUF_ALLOC*PBUF_LEN_MAX;
+ rxch->inactive_head->flags_pktlen = EMAC_DSC_FLAG_OWNER;
+ rxch->inactive_head->next = rxch->inactive_head + 1;
+ curr_rxbd = rxch->inactive_head;
+
+ num_bd = ((SIZE_EMAC_CTRL_RAM >> 1) / sizeof(struct emac_rx_bd))-1;
+
+ while (num_bd > 0) {
+ curr_rxbd = curr_rxbd->next;
+ curr_rxbd->next = curr_rxbd + 1;
+ curr_rxbd->flags_pktlen = EMAC_DSC_FLAG_OWNER;
+ curr_rxbd->pbuf = NULL;
+ num_bd--;
+ }
+ curr_rxbd->next = NULL;
+ rxch->inactive_tail = curr_rxbd;
+ rxch->active_tail = NULL;
+ rxch->active_head = NULL;
+#if TMS570_NETIF_DEBUG
+ tms570_eth_debug_show_rx(nf_state);
+ tms570_eth_debug_show_tx(nf_state);
+#endif
+
+}
+
+/* send and receive functions / ISRs ******************************************/
+
+static err_t
+tms570_eth_send(struct netif *netif, struct pbuf *p)
+{
+ err_t retVal = ERR_OK;
+
+ SYS_ARCH_DECL_PROTECT(lev);
+
+ /**
+ * This entire function must be protected to preserve
+ * the integrity of the transmit pbuf queue.
+ */
+ SYS_ARCH_PROTECT(lev);
+#if !SYS_LIGHTWEIGHT_PROT
+ sys_prot_t prevProt = sys_arch_protect()
+ /*
+ uint32_t prevProt = (uint32_t) _get_CPSR() & 0x80;
+ _disable_IRQ();
+ */
+#endif
+
+ /**
+ * Bump the reference count on the pbuf to prevent it from being
+ * freed until we are done with it.
+ */
+ pbuf_ref(p);
+
+ /* call the actual transmit function */
+ retVal = tms570_eth_send_raw(netif, p);
+
+ /* Return to prior interrupt state and return. */
+ SYS_ARCH_UNPROTECT(lev);
+#if !SYS_LIGHTWEIGHT_PROT
+ sys_arch_unprotect(prevProt);
+ /*
+ if (!prevProt)
+ _enable_IRQ();
+ */
+#endif
+
+ return retVal;
+}
+
+/**
+ * When called from tms570_eth_send(), the 'lev' lock is held
+ */
+static err_t
+tms570_eth_send_raw(struct netif *netif, struct pbuf *pbuf)
+{
+ struct pbuf *q;
+ struct txch *txch;
+ struct tms570_netif_state *nf_state;
+ unsigned int pktlen;
+ unsigned int padlen = 0;
+ volatile struct emac_tx_bd *curr_bd;
+ volatile struct emac_tx_bd *packet_head;
+ volatile struct emac_tx_bd *packet_tail;
+
+ nf_state = (struct tms570_netif_state *)netif->state;
+ txch = &(nf_state->txch);
+
+ /* Get the first BD that is unused and will be used for TX */
+ curr_bd = txch->inactive_head;
+ if (curr_bd == NULL)
+ goto error_out_of_descriptors;
+
+ packet_head = curr_bd;
+ packet_tail = curr_bd;
+
+ /* adjust the packet length if less than minimum required */
+ pktlen = pbuf->tot_len;
+ if (pktlen < MIN_PKT_LEN) {
+ padlen = MIN_PKT_LEN - pktlen;
+ pktlen = MIN_PKT_LEN;
+ }
+
+ /* First 'part' of packet flags */
+ curr_bd->flags_pktlen = pktlen | EMAC_DSC_FLAG_SOP |
+ EMAC_DSC_FLAG_OWNER;
+
+ /* Copy pbuf information into TX BDs --
+ * remember that the pbuf for a single packet might be chained!
+ */
+ for (q = pbuf; q != NULL; q = q->next) {
+ if (curr_bd == NULL)
+ goto error_out_of_descriptors;
+
+ curr_bd->bufptr = (uint8_t *)(q->payload);
+ curr_bd->bufoff_len = (q->len) & 0xFFFF;
+
+ /* This is an extra field that is not par of the in-HW BD.
+ * This is used when freeing the pbuf after the TX processing
+ * is done in EMAC
+ */
+ curr_bd->pbuf = pbuf;
+ packet_tail = curr_bd;
+ curr_bd = curr_bd->next;
+ }
+ if (padlen) {
+ if (curr_bd == NULL)
+ goto error_out_of_descriptors;
+
+ /* If the ETHERNET packet is smaller than 64 bytes, it has
+ * to be padded. We need some data and do not want to leak
+ * random memory. Reuse IP and possibly TCP/UDP header
+ * of given frame as padding
+ */
+ curr_bd->bufptr = packet_head->bufptr;
+ curr_bd->bufoff_len = padlen;
+ curr_bd->pbuf = pbuf;
+ packet_tail = curr_bd;
+ curr_bd = curr_bd->next;
+ }
+ /* Indicate the end of the packet */
+ packet_tail->next = NULL;
+ packet_tail->flags_pktlen |= EMAC_DSC_FLAG_EOP;
+
+ txch->inactive_head = curr_bd;
+ if (curr_bd == NULL)
+ txch->inactive_tail = curr_bd;
+
+ sys_arch_data_sync_barier();
+
+ if (txch->active_tail == NULL) {
+ txch->active_head = packet_head;
+ tms570_eth_hw_set_TX_HDP(nf_state, packet_head);
+ } else {
+ /* Chain the bd's. If the DMA engine already reached the
+ * end of the chain, the EOQ will be set. In that case,
+ * the HDP shall be written again.
+ */
+ txch->active_tail->next = packet_head;
+ curr_bd = txch->active_tail;
+
+ /* We were too slow and the EMAC already read the
+ * 'pNext = NULL' of the former txch->active_tail. In this
+ * case the transmission stopped and we need to write the
+ * pointer to newly added BDs to the TX HDP
+ */
+ if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOQ) {
+ tms570_eth_hw_set_TX_HDP(nf_state, packet_head);
+ }
+ }
+ txch->active_tail = packet_tail;
+
+ return ERR_OK;
+
+error_out_of_descriptors:
+ pbuf_free(pbuf);
+ return ERR_IF;
+}
+
+/* EMAC Packet Buffer Sizes and Placement */
+#ifdef CONFIG_EMAC_PKT_FRAG_SIZE
+ #define EMAC_FRAG_SIZE CONFIG_EMAC_PKT_FRAG_SIZE
+#else
+ #define EMAC_FRAG_SIZE 1536
+#endif
+
+#ifdef CONFIG_EMAC_ETH_FRAME_SIZE
+ #define EMAC_MAX_FLEN CONFIG_EMAC_ETH_FRAME_SIZE
+#else
+ #define EMAC_MAX_FLEN 1536
+#endif
+
+#ifdef CONFIG_EMAC_NUM_RX_FRAGS
+ #define EMAC_NUM_RX_FRAG CONFIG_EMAC_NUM_RX_FRAGS
+#else
+ #define EMAC_NUM_RX_FRAG 4
+#endif
+
+#ifdef CONFIG_EMAC_NUM_TX_FRAGS
+ #define EMAC_NUM_TX_FRAG CONFIG_EMAC_NUM_TX_FRAGS
+#else
+ #define EMAC_NUM_TX_FRAG 2
+#endif
+
+static void
+tms570_eth_process_irq_rx(void *arg)
+{
+ struct tms570_netif_state *nf_state;
+ struct rxch *rxch;
+ struct netif *netif = (struct netif *)arg;
+ volatile struct emac_rx_bd *curr_bd;
+ struct pbuf *pbuf;
+ struct pbuf *q;
+
+ nf_state = netif->state;
+ rxch = &(nf_state->rxch);
+ /* Get the bd which contains the earliest filled data */
+ curr_bd = rxch->active_head;
+ if (curr_bd == NULL) {
+ tms570_eth_rx_pbuf_refill(nf_state, 0);
+ return;
+ }
+
+ /* For each valid frame */
+ while ((curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP) &&
+ !(curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER)) {
+ unsigned int total_rx_len;
+ unsigned int processed_rx_len = 0;
+ int corrupt_fl = 0;
+
+ sys_arch_data_sync_barier();
+
+ pbuf = curr_bd->pbuf;
+ total_rx_len = curr_bd->flags_pktlen & 0xFFFF;
+ tms570_eth_debug_printf("recieve packet. L = %d ", total_rx_len);
+ /* The received frame might be fragmented into muliple
+ * pieces -- each one referenced by a separate BD.
+ * To further process the data, we need to 'make' a
+ * proper PBUF out of it -- that means linking each
+ * buffer together, copy the length information form
+ * the DB to PBUF, calculate the 'tot_len' etc.
+ */
+ for (;; ) {
+ q = curr_bd->pbuf;
+ /* Since this pbuf will be freed, we need to
+ * keep track of its size to be able to
+ * allocate it back again
+ */
+ rxch->freed_pbuf_len += q->len;
+ tms570_eth_debug_printf("bd - %d ", tms570_eth_debug_get_BD_num(curr_bd, nf_state));
+ tms570_eth_debug_printf("pbuf len - %d ", q->len);
+ tms570_eth_debug_printf("A - 0x%08x ", q);
+ /* This is the size of the "received data" not the PBUF */
+ q->tot_len = total_rx_len - processed_rx_len;
+ q->len = curr_bd->bufoff_len & 0xFFFF;
+
+ if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOP)
+ break;
+ /*
+ * If we are executing here, it means this
+ * packet is being split over multiple BDs
+ */
+ tms570_eth_debug_printf("MB");
+ /* chain the pbufs since they belong
+ * to the same packet
+ */
+ if (curr_bd->next == NULL) {
+ corrupt_fl = 1;
+ break;
+ }
+ curr_bd = curr_bd->next;
+ q->next = curr_bd->pbuf;
+
+ processed_rx_len += q->len;
+ }
+ tms570_eth_debug_printf("\n");
+ /* Close the chain */
+ q->next = NULL;
+ if (rxch->inactive_tail == NULL) {
+ rxch->inactive_head = rxch->active_head;
+ } else {
+ rxch->inactive_tail->next = rxch->active_head;
+ }
+ rxch->inactive_tail = curr_bd;
+ rxch->active_head = curr_bd->next;
+ if (curr_bd->next == NULL)
+ rxch->active_tail = NULL;
+ rxch->inactive_tail->next = NULL;
+
+
+ LINK_STATS_INC(link.recv);
+
+ /* Process the packet */
+ /* ethernet_input((struct pbuf *)pbuf, netif) */
+ if (!corrupt_fl)
+ if (netif->input(pbuf, netif) != ERR_OK)
+ corrupt_fl = 1;
+ if (corrupt_fl) {
+ LINK_STATS_INC(link.memerr);
+ LINK_STATS_INC(link.drop);
+ pbuf_free(pbuf);
+ }
+
+ /* Acknowledge that this packet is processed */
+ EMACRxCPWrite(nf_state->emac_base, 0, (unsigned int)curr_bd);
+
+ /* The earlier PBUF chain is freed from the upper layer.
+ * So, we need to allocate a new pbuf chain and update
+ * the descriptors with the PBUF info.
+ * Care should be taken even if the allocation fails.
+ */
+ tms570_eth_rx_pbuf_refill(nf_state, 0);
+ //tms570_eth_debug_print_rxch();
+ curr_bd = rxch->active_head;
+ if (curr_bd == NULL) {
+ return;
+ }
+ }
+}
+
+static void
+tms570_eth_process_irq_tx(void *arg)
+{
+
+ struct txch *txch;
+ volatile struct emac_tx_bd *curr_bd;
+ volatile struct emac_tx_bd *start_of_packet_bd;
+ struct netif *netif = (struct netif *)arg;
+ struct tms570_netif_state *nf_state;
+
+ nf_state = netif->state;
+ txch = &(nf_state->txch);
+
+ start_of_packet_bd = txch->active_head;
+ curr_bd = txch->active_head;
+
+ /* Traverse the list of BDs used for transmission --
+ * stop on the first unused
+ */
+ while ((curr_bd != NULL) && (curr_bd->flags_pktlen & EMAC_DSC_FLAG_SOP)) {
+ /* Make sure the transmission is over */
+ if (curr_bd->flags_pktlen & EMAC_DSC_FLAG_OWNER) {
+ tms570_eth_debug_printf("TXthread ownership not transfered!!!!\n");
+ break;
+ }
+
+ /* Find the last chunk of the packet */
+ while (!(curr_bd->flags_pktlen & EMAC_DSC_FLAG_EOP))
+ curr_bd = curr_bd->next;
+
+ /* Remove flags for the transmitted BDs */
+ start_of_packet_bd->flags_pktlen &= (~EMAC_DSC_FLAG_SOP);
+ curr_bd->flags_pktlen &= (~EMAC_DSC_FLAG_EOP);
+
+ /*
+ * Return processed BDs to inactive list
+ */
+ if (txch->inactive_tail == NULL) {
+ txch->inactive_head = start_of_packet_bd;
+ } else {
+ txch->inactive_tail->next = start_of_packet_bd;
+ }
+ txch->inactive_tail = curr_bd;
+
+ /*
+ * Remove BDs from active list
+ */
+ txch->active_head = curr_bd->next;
+ if (curr_bd->next == NULL) {
+ txch->active_tail = NULL;
+ }
+
+ /*
+ * Insert null element at the end of the inactive list
+ */
+ txch->inactive_tail->next = NULL;
+
+
+ /* Ack the Interrupt in the EMAC peripheral */
+ EMACTxCPWrite(nf_state->emac_base, CHANNEL,
+ (uint32_t)curr_bd);
+
+ /* Free the corresponding pbuf
+ * Sidenote: Each fragment of the single packet points
+ * to the same pbuf
+ */
+ pbuf_free(start_of_packet_bd->pbuf);
+
+ LINK_STATS_INC(link.xmit);
+
+ /* Move to the next packet */
+ start_of_packet_bd = txch->active_head;
+ curr_bd = txch->active_head;
+ }
+}
+
+static void
+tms570_eth_process_irq(void *argument)
+{
+ struct netif *netif = (struct netif *)argument;
+ struct tms570_netif_state *nf_state;
+ uint32_t macints;
+
+ nf_state = netif->state;
+
+ if (nf_state == NULL)
+ return;
+
+ while (1) {
+ macints = nf_state->emac_base->MACINVECTOR;
+ if ((macints & 0xffff) == 0) {
+ break;
+ }
+ if (macints & (0xff<<16)) { //TX interrupt
+ tms570_eth_process_irq_tx(netif);
+ EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_TX);
+ }
+ if (macints & (0xff<<0)) { //RX interrupt
+ tms570_eth_process_irq_rx(netif);
+ EMACCoreIntAck(nf_state->emac_base, EMAC_INT_CORE0_RX);
+ }
+ }
+ sys_arch_unmask_interrupt_source(TMS570_IRQ_EMAC_RX);
+ sys_arch_unmask_interrupt_source(TMS570_IRQ_EMAC_TX);
+}
+
+void static
+tms570_eth_process_irq_request(void *argument)
+{
+ struct netif *netif = (struct netif *)argument;
+ struct tms570_netif_state *nf_state;
+
+ nf_state = netif->state;
+
+ for (;; ) {
+ sys_arch_sem_wait(&nf_state->intPend_sem, 0);
+ tcpip_callback((tcpip_callback_fn)tms570_eth_process_irq, netif);
+ }
+}
+
+static void
+tms570_eth_hw_set_RX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_rx_bd *new_head)
+{
+ /* Writes to RX HDP are allowed
+ * only when it is 0
+ */
+ while (nf_state->emac_base->RXHDP[CHANNEL] != 0) {
+ tms570_eth_debug_printf("HW -RX- is slacking!!!\n");
+ sys_arch_delay(10);
+ }
+ tms570_eth_debug_printf("setting RX HDP");
+ EMACRxHdrDescPtrWrite(
+ nf_state->emac_base,
+ (uint32_t)new_head,
+ CHANNEL);
+}
+static void
+tms570_eth_hw_set_TX_HDP(struct tms570_netif_state *nf_state, volatile struct emac_tx_bd *new_head)
+{
+ /* Writes to RX HDP are allowed
+ * only when it is 0
+ */
+ while (nf_state->emac_base->TXHDP[CHANNEL] != 0) {
+ tms570_eth_debug_printf("HW -TX- is slacking!!!\n");
+ sys_arch_delay(10);
+ }
+ tms570_eth_debug_printf("setting TX HDP");
+ EMACTxHdrDescPtrWrite(
+ nf_state->emac_base,
+ (uint32_t)new_head,
+ CHANNEL);
+}
+
+static void
+tms570_eth_rx_pbuf_refill_single(struct netif *netif)
+{
+ tms570_eth_rx_pbuf_refill(netif->state, 1);
+}
+
+static void
+tms570_eth_rx_pbuf_refill(struct tms570_netif_state *nf_state, int single_fl)
+{
+ struct rxch *rxch;
+ volatile struct emac_rx_bd *curr_bd;
+ volatile struct emac_rx_bd *curr_head;
+ struct pbuf *new_pbuf;
+ struct pbuf *q;
+ uint32_t alloc_rq_bytes;
+
+ rxch = &(nf_state->rxch);
+ if (single_fl) {
+ alloc_rq_bytes = PBUF_POOL_BUFSIZE;
+ } else {
+ alloc_rq_bytes = rxch->freed_pbuf_len;
+ }
+
+ for (; (rxch->freed_pbuf_len > 0) && (rxch->inactive_head != NULL); ) {
+ //stats_display();
+
+ curr_bd = rxch->inactive_head;
+ curr_head = rxch->inactive_head;
+ tms570_eth_debug_printf("attempt to allocate %d bytes from pbuf pool (RX)\n", alloc_rq_bytes);
+ new_pbuf = pbuf_alloc(PBUF_RAW,
+ alloc_rq_bytes,
+ PBUF_POOL);
+ if (new_pbuf == NULL) {
+ #if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__)
+ alloc_rq_bytes = (1 << (30-__builtin_clz(alloc_rq_bytes)));
+ #else /*__GNUC__*/
+ {
+ int n = 0;
+ while ((1 << n) < alloc_rq_bytes)
+ n++;
+ alloc_rq_bytes = 1 << (n - 1);
+ }
+ #endif /*__GNUC__*/
+ if (alloc_rq_bytes <= PBUF_POOL_BUFSIZE) {
+ tms570_eth_debug_printf("not enough memory\n");
+ break;
+ }
+ alloc_rq_bytes = rxch->freed_pbuf_len > alloc_rq_bytes ?
+ alloc_rq_bytes : rxch->freed_pbuf_len;
+ continue;
+ } else {
+ q = new_pbuf;
+ for (;; ) {
+ curr_bd->bufptr = (uint8_t *)q->payload;
+ curr_bd->bufoff_len = q->len;
+ curr_bd->flags_pktlen = EMAC_DSC_FLAG_OWNER;
+ curr_bd->pbuf = q;
+ rxch->freed_pbuf_len -= q->len;
+ q = q->next;
+ if (q == NULL)
+ break;
+ if (curr_bd->next == NULL) {
+ rxch->inactive_tail = NULL;
+ break;
+ }
+ curr_bd = curr_bd->next;
+ }
+
+ if (q != NULL)
+ pbuf_free((struct pbuf *)q);
+ /* Add the newly allocated BDs to the
+ * end of the list
+ */
+ rxch->inactive_head = curr_bd->next;
+
+ curr_bd->next = NULL;
+ sys_arch_data_sync_barier();
+
+ if (rxch->active_head == NULL) {
+ rxch->active_head = curr_head;
+ rxch->active_tail = curr_bd;
+ tms570_eth_hw_set_RX_HDP(nf_state, rxch->active_head);
+ } else {
+ rxch->active_tail->next = curr_head;
+ sys_arch_data_sync_barier();
+ if ((rxch->active_tail->flags_pktlen & EMAC_DSC_FLAG_EOQ) != 0)
+ tms570_eth_hw_set_RX_HDP(nf_state, rxch->active_head);
+ rxch->active_tail = curr_bd;
+ }
+ }
+ }
+}
+
+#if !defined(__TI_COMPILER_VERSION__)
+static
+#endif /*__TI_COMPILER_VERSION__*/
+SYS_IRQ_HANDLER_FNC(tms570_eth_irq){
+ struct tms570_netif_state *nf_state = (struct tms570_netif_state *)sys_irq_handler_get_context();
+
+ sys_arch_mask_interrupt_source(TMS570_IRQ_EMAC_RX);
+ sys_arch_mask_interrupt_source(TMS570_IRQ_EMAC_TX);
+ if (nf_state != NULL)
+ sys_sem_signal_from_ISR(&nf_state->intPend_sem);
+}
+
+void
+tms570_eth_memp_avaible(int type)
+{
+ if (!initialized)
+ return;
+ if (type != MEMP_PBUF_POOL)
+ return;
+ netifapi_netif_common(eth_lwip_get_netif(0), tms570_eth_rx_pbuf_refill_single, NULL);
+}
+
+
+
+#if TMS570_NETIF_DEBUG
+
+void
+tms570_eth_debug_print_info(struct netif *netif)
+{
+ struct tms570_netif_state *nf_state = netif->state;
+
+ tms570_eth_debug_show_rx(nf_state);
+ tms570_eth_debug_show_tx(nf_state);
+ tms570_eth_debug_print_HDP(nf_state);
+}
+
+void
+tms570_eth_debug_print_HDP(struct tms570_netif_state *nf_state)
+{
+ tms570_eth_debug_printf("RX HDP = %d\n", tms570_eth_debug_get_BD_num(
+ (void *)nf_state->emac_base->RXHDP[0], nf_state));
+ tms570_eth_debug_printf("TX HDP = %d\n", tms570_eth_debug_get_BD_num(
+ (void *)nf_state->emac_base->TXHDP[0], nf_state));
+}
+
+int
+tms570_eth_debug_get_BD_num(volatile void *ptr, struct tms570_netif_state *nf_state)
+{
+ if (ptr == NULL)
+ return -1;
+ return ((uintptr_t)ptr-nf_state->emac_ctrl_ram)/sizeof(struct emac_rx_bd);
+}
+
+void
+tms570_eth_debug_print_rxch(struct tms570_netif_state *nf_state)
+{
+ tms570_eth_debug_printf("inactive_head = %d, inactive_tail = %d, active_head = %d, active_tail = %d, freed_pbuf_len = %d\n",
+ tms570_eth_debug_get_BD_num(nf_state->rxch.inactive_head, nf_state),
+ tms570_eth_debug_get_BD_num(nf_state->rxch.inactive_tail, nf_state),
+ tms570_eth_debug_get_BD_num(nf_state->rxch.active_head, nf_state),
+ tms570_eth_debug_get_BD_num(nf_state->rxch.active_tail, nf_state),
+ nf_state->rxch.freed_pbuf_len);
+}
+void
+tms570_eth_debug_print_txch(struct tms570_netif_state *nf_state)
+{
+ tms570_eth_debug_printf("inactive_head = %d, inactive_tail = %d, active_head = %d, active_tail = %d\n",
+ tms570_eth_debug_get_BD_num(nf_state->txch.inactive_head, nf_state),
+ tms570_eth_debug_get_BD_num(nf_state->txch.inactive_tail, nf_state),
+ tms570_eth_debug_get_BD_num(nf_state->txch.active_head, nf_state),
+ tms570_eth_debug_get_BD_num(nf_state->txch.active_tail, nf_state));
+}
+void
+tms570_eth_debug_show_BD_chain_rx(volatile struct emac_rx_bd *curr_bd,
+ struct tms570_netif_state *nf_state)
+{
+ int count = 0;
+
+ while (curr_bd != NULL) {
+ tms570_eth_debug_printf("%d ", tms570_eth_debug_get_BD_num(curr_bd, nf_state));
+ curr_bd = curr_bd->next;
+ count++;
+ }
+ tms570_eth_debug_printf(" count = %d\n", count);
+}
+
+void
+tms570_eth_debug_show_BD_chain_tx(volatile struct emac_tx_bd *curr_bd,
+ struct tms570_netif_state *nf_state)
+{
+ int count = 0;
+
+ while (curr_bd != NULL) {
+ tms570_eth_debug_printf("%d ", tms570_eth_debug_get_BD_num(curr_bd, nf_state));
+ curr_bd = curr_bd->next;
+ count++;
+ }
+ tms570_eth_debug_printf(" count = %d\n", count);
+}
+
+void
+tms570_eth_debug_show_rx(struct tms570_netif_state *nf_state)
+{
+ tms570_eth_debug_printf("!!!RX!!!\n");
+ tms570_eth_debug_print_rxch(nf_state);
+ tms570_eth_debug_printf("inactive chain\n");
+ tms570_eth_debug_show_BD_chain_rx(nf_state->rxch.inactive_head, nf_state);
+ tms570_eth_debug_printf("active chain\n");
+ tms570_eth_debug_show_BD_chain_rx(nf_state->rxch.active_head, nf_state);
+}
+void
+tms570_eth_debug_show_tx(struct tms570_netif_state *nf_state)
+{
+
+ tms570_eth_debug_printf("!!!TX!!!\n");
+ tms570_eth_debug_print_txch(nf_state);
+ tms570_eth_debug_printf("inactive chain\n");
+ tms570_eth_debug_show_BD_chain_tx(nf_state->txch.inactive_head, nf_state);
+ tms570_eth_debug_printf("active chain\n");
+ tms570_eth_debug_show_BD_chain_tx(nf_state->txch.active_head, nf_state);
+}
+#endif /* if TMS570_NETIF_DEBUG */
diff --git a/uLan/ports/driver/tms570_emac/tms570_netif.h b/uLan/ports/driver/tms570_emac/tms570_netif.h
new file mode 100644
index 0000000..325249a
--- /dev/null
+++ b/uLan/ports/driver/tms570_emac/tms570_netif.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, 2015 Czech Technical University in Prague
+ * Czech Republic
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Author: Premysl Houdek <houdepre@fel.cvut.cz>
+ * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Industrial Informatics Group, FEE, Czech Technical University in Prague
+ *
+ * Based on work of Carlos Jenkins, Rostislav Lisovy, Jan Dolezal
+ */
+
+#ifndef __TMS570_NETIF_H
+#define __TMS570_NETIF_H
+
+//#define TMS570_NETIF_DEBUG 1
+
+#ifdef TMS570_NETIF_DEBUG
+#define tms570_eth_debug_printf sys_arch_printk
+#else
+#define tms570_eth_debug_printf(...)
+#endif
+
+err_t tms570_eth_init_netif(struct netif *netif);
+struct tms570_netif_state *tms570_eth_init_state();
+
+#if TMS570_NETIF_DEBUG
+struct emac_rx_bd;
+int tms570_eth_debug_get_BD_num(volatile void *ptr, struct tms570_netif_state *nf_state);
+void tms570_eth_debug_print_rxch(struct tms570_netif_state *nf_state);
+void tms570_eth_debug_print_txch(struct tms570_netif_state *nf_state);
+void tms570_eth_debug_show_BD_chain(volatile struct emac_rx_bd *curr_bd, struct tms570_netif_state *nf_state);
+void tms570_eth_debug_show_rx(struct tms570_netif_state *nf_state);
+void tms570_eth_debug_show_tx(struct tms570_netif_state *nf_state);
+void tms570_eth_debug_print_HDP(struct tms570_netif_state *nf_state);
+void tms570_eth_debug_print_info(struct netif *netif);
+#endif /* TMS570_NETIF_DEBUG */
+
+#endif /* __TMS570_NETIF_H */
diff --git a/uLan/ports/os/lwipopts.h b/uLan/ports/os/lwipopts.h
new file mode 100644
index 0000000..50ac639
--- /dev/null
+++ b/uLan/ports/os/lwipopts.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Simon Goldschmidt
+ *
+ */
+#ifndef LWIP_HDR_LWIPOPTS_H__
+#define LWIP_HDR_LWIPOPTS_H__
+
+/* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
+#define NO_SYS 0
+#define LWIP_NETCONN 1
+#define LWIP_SOCKET 1
+#define LWIP_DNS 1
+
+#define LWIP_IPV6 1
+#define LWIP_IPV4 1
+
+#define LWIP_ETHERNET 1
+#define LWIP_NETIF_API 1
+/* Enable DHCP to test it, disable UDP checksum to easier inject packets */
+#define LWIP_DHCP 1
+#define LWIP_TIMEVAL_PRIVATE 0
+#define LWIP_POSIX_SOCKETS_IO_NAMES 0
+
+/* Minimal changes to opt.h required for tcp unit tests: */
+#define MEM_SIZE 16000
+#define TCP_SND_QUEUELEN 40
+#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN
+#define TCP_SND_BUF (12 * TCP_MSS)
+#define TCP_WND (10 * TCP_MSS)
+#define LWIP_WND_SCALE 1
+#define TCP_RCV_SCALE 0
+#define PBUF_POOL_SIZE 400 // pbuf tests need ~200KByte
+
+/* Minimal changes to opt.h required for etharp unit tests: */
+#define ETHARP_SUPPORT_STATIC_ENTRIES 1
+
+#endif /* LWIP_HDR_LWIPOPTS_H__ */
diff --git a/uLan/ports/os/rtems/arch/cc.h b/uLan/ports/os/rtems/arch/cc.h
new file mode 100644
index 0000000..84138ff
--- /dev/null
+++ b/uLan/ports/os/rtems/arch/cc.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is system adaptation of the lwIP TCP/IP stack
+ * by Adam Dunkels <adam@sics.se> for RTEMS system.
+ *
+ * Author: Premysl Houdek <houdepre@fel.cvut.cz>
+ * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Industrial Informatics Group, FEE, Czech Technical University in Prague
+ *
+ */
+/*
+ * settings to adapt lwIP for compiler and machine architecture for RTEMS/GCC
+ * DETAILS: ./lwip/doc/sys_arch.txt
+ */
+#ifndef __CC_H__
+#define __CC_H__
+
+#include <stdio.h>
+#include <rtems/malloc.h> /*printk*/
+#include <inttypes.h>
+#include <malloc.h>
+#include <sys/time.h>
+#include <rtems.h>
+#include <sys/errno.h>
+#include <endian.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <sys/uio.h> /*struct iovec*/
+
+#ifndef iovec
+#define iovec iovec
+#endif
+
+/* This file must either include a system-local <errno.h> which defines
+ the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
+ to make lwip/arch.h define the codes which are used throughout. */
+#undef LWIP_PROVIDE_ERRNO
+
+#if !defined(LWIP_NO_STDINT_H)
+#define LWIP_NO_STDINT_H 0
+#endif
+
+#if LWIP_NO_STDINT_H
+/* type definitions */
+typedef uint8_t u8_t;
+typedef int8_t s8_t;
+typedef uint16_t u16_t;
+typedef int16_t s16_t;
+typedef uint32_t u32_t;
+typedef int32_t s32_t;
+typedef u32_t mem_ptr_t;
+
+#endif /*LWIP_NO_STDINT_H*/
+
+#if !defined(LWIP_NO_INTTYPES_H)
+#define LWIP_NO_INTTYPES_H 0
+#endif
+
+#if LWIP_NO_INTTYPES_H
+/* Define (sn)printf formatters for these lwIP types */
+#define U16_F PRIu16
+#define S16_F PRId16
+#define X16_F PRIx16
+#define U32_F PRIu32
+#define S32_F PRId32
+#define X32_F PRIx32
+#endif /*LWIP_NO_INTTYPES_H*/
+
+#if defined(__arm__) && defined(__ARMCC_VERSION)
+//
+// Setup PACKing macros for KEIL/RVMDK Tools
+//
+ #define PACK_STRUCT_BEGIN __packed
+ #define PACK_STRUCT_STRUCT
+ #define PACK_STRUCT_END
+ #define PACK_STRUCT_FIELD(x) x
+#elif defined (__IAR_SYSTEMS_ICC__)
+//
+// Setup PACKing macros for IAR Tools
+//
+ #define PACK_STRUCT_BEGIN
+ #define PACK_STRUCT_STRUCT
+ #define PACK_STRUCT_END
+ #define PACK_STRUCT_FIELD(x) x
+ #define PACK_STRUCT_USE_INCLUDES
+#elif defined (__TMS470__)
+ #define PACK_STRUCT_BEGIN
+ #define PACK_STRUCT_STRUCT
+ #define PACK_STRUCT_END
+ #define PACK_STRUCT_FIELD(x) x
+#else
+//
+// Setup PACKing macros for GCC Tools
+//
+ #define PACK_STRUCT_BEGIN
+ #define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
+ #define PACK_STRUCT_END
+ #define PACK_STRUCT_FIELD(x) x
+#endif
+
+/*
+ * 1 - load byte by byte, construct 16 bits word and add: not efficient for most platforms
+ * 2 - load first byte if odd address, loop processing 16 bits words, add last byte.
+ * 3 - load first byte and word if not 4 byte aligned, loop processing 32 bits words, add last word/byte.
+ *
+ * see inet_chksum.c
+ */
+#ifndef LWIP_CHKSUM_ALGORITHM
+#define LWIP_CHKSUM_ALGORITHM 2
+#endif
+
+/* this is used for 1) displaying statistics and 2) lwip debugging (set appropriate debugging level in lwipopts.h) */
+//#ifdef LWIP_DEBUG
+
+
+#define LWIP_PLATFORM_DIAG(expr) printk expr
+
+//#else
+//#define LWIP_PLATFORM_DIAG(expr)
+//#endif
+
+//#define DEBUG
+#ifdef DEBUG
+
+/* for passing arguments to print function */
+#define CC_ASSERT(message, assertion) do { if (!(assertion)) \
+ LWIP_PLATFORM_DIAG(message); } while (0)
+
+//extern void __error__(char *pcFilename, unsigned long ulLine);
+#define LWIP_PLATFORM_ASSERT(expr) printk((const char *)expr)
+/*
+{ \
+ if(!(expr)) \
+ { \
+ __error__(__FILE__, __LINE__); \
+ } \
+}
+*/
+#else
+#define LWIP_PLATFORM_ASSERT(expr)
+#define CC_ASSERT(message, assertion)
+#endif /* DEBUG */
+
+/* "lightweight" synchronization mechanisms */
+/* #define SYS_ARCH_DECL_PROTECT(x) */ /* declare a protection state variable */
+/* #define SYS_ARCH_PROTECT(x) */ /* enter protection mode */
+/* #define SYS_ARCH_UNPROTECT(x) */ /* leave protection mode */
+
+/* 32-bit random value used by igmp and others */
+#define LWIP_RAND() ((uint32_t)random())
+
+#endif /* __CC_H__ */
diff --git a/uLan/ports/os/rtems/arch/perf.h b/uLan/ports/os/rtems/arch/perf.h
new file mode 100644
index 0000000..1f799b3
--- /dev/null
+++ b/uLan/ports/os/rtems/arch/perf.h
@@ -0,0 +1,12 @@
+#ifndef _LWIP_ARCH_PERF_H_
+#define _LWIP_ARCH_PERF_H_
+
+//perf.h - Architecture specific performance measurement.
+//Measurement calls made throughout lwip, these can be defined to nothing.
+
+#define PERF_START
+
+#define PERF_STOP(x)
+
+
+#endif /* _LWIP_ARCH_PERF_H_ */
diff --git a/uLan/ports/os/rtems/arch/sys_arch.c b/uLan/ports/os/rtems/arch/sys_arch.c
new file mode 100644
index 0000000..ca7f8be
--- /dev/null
+++ b/uLan/ports/os/rtems/arch/sys_arch.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is system adaptation of the lwIP TCP/IP stack
+ * by Adam Dunkels <adam@sics.se> for RTEMS system.
+ *
+ * Author: Premysl Houdek <houdepre@fel.cvut.cz>
+ * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Industrial Informatics Group, FEE, Czech Technical University in Prague
+ *
+ */
+/*
+ * mapping of lwIP system dependencies to RTEMS system services and types.
+ * DETAILS: ./lwip/doc/sys_arch.txt
+ */
+
+#include <stdint.h>
+#include <arch/cc.h>
+#include <rtems/rtems/clock.h>
+#include <rtems/rtems/sem.h>
+#include <rtems.h>
+#include "sys_arch.h"
+#include "lwip/err.h"
+#include "lwip/tcpip.h"
+#include "lwipopts.h"
+
+#define SYS_LWIP_MBOX_SIZE (sizeof(void *))
+
+uint32_t
+sys_now()
+{
+ uint64_t temp = rtems_clock_get_uptime_nanoseconds() / (1000 * 1000);
+
+ return temp;
+}
+
+void
+sys_init(void)
+{
+ // Is called to initialize the sys_arch layer.
+ return;
+}
+
+err_t
+sys_sem_new(sys_sem_t *sem, u8_t count)
+{
+ rtems_status_code ret = rtems_semaphore_create(
+ rtems_build_name('L', 'W', 'I', 'P'),
+ count,
+ RTEMS_COUNTING_SEMAPHORE,
+ 0,
+ &sem->semaphore
+ );
+
+ if (ret != RTEMS_SUCCESSFUL) {
+ sem->semaphore = RTEMS_ID_NONE;
+ return ret;
+ }
+ return ERR_OK;
+}
+
+
+void
+sys_sem_free(sys_sem_t *sem)
+{
+ rtems_semaphore_delete(
+ sem->semaphore
+ );
+ sem->semaphore = RTEMS_ID_NONE;
+}
+
+void
+sys_sem_signal(sys_sem_t *sem)
+{
+ rtems_semaphore_release(sem->semaphore);
+}
+
+void
+sys_sem_signal_from_ISR(sys_sem_t *sem)
+{
+ rtems_semaphore_release(sem->semaphore);
+}
+
+
+u32_t
+sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
+{
+ rtems_status_code status;
+ rtems_interval tps = rtems_clock_get_ticks_per_second();
+ rtems_interval tick_timeout;
+ uint64_t start_time;
+ uint64_t wait_time;
+
+ start_time = rtems_clock_get_uptime_nanoseconds();
+ if (timeout == 0) {
+ tick_timeout = RTEMS_NO_TIMEOUT;
+ } else {
+ tick_timeout = (timeout * tps + 999) / 1000;
+ }
+ status = rtems_semaphore_obtain(sem->semaphore, RTEMS_WAIT, tick_timeout);
+ if (status == RTEMS_TIMEOUT) {
+ return SYS_ARCH_TIMEOUT;
+ }
+ if (status != RTEMS_SUCCESSFUL) {
+ return SYS_ARCH_TIMEOUT;
+ }
+ wait_time = rtems_clock_get_uptime_nanoseconds() - start_time;
+ return wait_time / (1000 * 1000);
+}
+
+int
+sys_sem_valid(sys_sem_t *sem)
+{
+ return sem->semaphore == RTEMS_ID_NONE ? 0 : 1;
+}
+
+void
+sys_sem_set_invalid(sys_sem_t *sem)
+{
+ sem->semaphore = RTEMS_ID_NONE;
+}
+
+err_t
+sys_mbox_new(sys_mbox_t *mbox, int size)
+{
+ rtems_status_code ret;
+
+ ret = rtems_message_queue_create(
+ rtems_build_name('L', 'W', 'I', 'P'),
+ size,
+ SYS_LWIP_MBOX_SIZE,
+ 0,
+ &mbox->mailbox
+ );
+ ret |= rtems_semaphore_create(
+ rtems_build_name('L', 'W', 'I', 'P'),
+ size,
+ RTEMS_COUNTING_SEMAPHORE,
+ 0,
+ &mbox->sem
+ );
+ if (ret != RTEMS_SUCCESSFUL) {
+ mbox->mailbox = RTEMS_ID_NONE;
+ mbox->sem = RTEMS_ID_NONE;
+ return ret;
+ }
+ return ERR_OK;
+}
+
+void
+sys_mbox_free(sys_mbox_t *mbox)
+{
+ rtems_message_queue_delete(mbox->mailbox);
+ rtems_semaphore_delete(mbox->sem);
+ sys_mbox_set_invalid(mbox);
+}
+
+void
+sys_mbox_post(sys_mbox_t *mbox, void *msg)
+{
+ rtems_semaphore_obtain(mbox->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ rtems_message_queue_send(mbox->mailbox, &msg, SYS_LWIP_MBOX_SIZE);
+}
+err_t
+sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
+{
+ rtems_status_code status = rtems_semaphore_obtain(mbox->sem,
+ RTEMS_NO_WAIT, 0);
+
+ if (status != RTEMS_SUCCESSFUL) {
+ return ERR_MEM;
+ } else {
+ rtems_message_queue_send(mbox->mailbox, &msg, SYS_LWIP_MBOX_SIZE);
+ return ERR_OK;
+ }
+}
+
+u32_t
+sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
+{
+ rtems_status_code status;
+ rtems_interval tps = rtems_clock_get_ticks_per_second();
+ rtems_interval tick_timeout;
+ uint64_t start_time;
+ uint64_t wait_time;
+ size_t dummy;
+
+ start_time = rtems_clock_get_uptime_nanoseconds();
+ if (timeout == 0) {
+ tick_timeout = RTEMS_NO_TIMEOUT;
+ } else {
+ tick_timeout = (timeout * tps + 999) / 1000;
+ }
+ status = rtems_message_queue_receive(mbox->mailbox,
+ msg,
+ &dummy,
+ RTEMS_WAIT,
+ tick_timeout
+ );
+ if (status == RTEMS_TIMEOUT) {
+ return SYS_ARCH_TIMEOUT;
+ }
+ if (status != RTEMS_SUCCESSFUL) {
+ return SYS_ARCH_TIMEOUT;
+ }
+ wait_time = rtems_clock_get_uptime_nanoseconds() - start_time;
+ rtems_semaphore_release(mbox->sem);
+ return wait_time / (1000 * 1000);
+}
+
+u32_t
+sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
+{
+ rtems_status_code status;
+ size_t dummy;
+
+ status = rtems_message_queue_receive(mbox->mailbox, msg,
+ &dummy,
+ RTEMS_NO_WAIT,
+ 0
+ );
+
+ if (status != RTEMS_SUCCESSFUL) {
+ return SYS_MBOX_EMPTY;
+ } else {
+ rtems_semaphore_release(mbox->sem);
+ return 0;
+ }
+}
+int
+sys_mbox_valid(sys_mbox_t *mbox)
+{
+ return mbox->mailbox == RTEMS_ID_NONE ? 0 : 1;
+}
+void
+sys_mbox_set_invalid(sys_mbox_t *mbox)
+{
+ mbox->sem = RTEMS_ID_NONE;
+ mbox->mailbox = RTEMS_ID_NONE;
+}
+
+sys_thread_t
+sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stack_size, int prio)
+{
+ rtems_id id;
+ rtems_status_code res;
+
+ res = rtems_task_create(
+ rtems_build_name('L', 'W', 'I', 'P'),
+ prio,
+ stack_size,
+ RTEMS_PREEMPT,
+ 0,
+ &id
+ );
+
+ if (res != RTEMS_SUCCESSFUL) {
+ return 0;
+ }
+
+ res = rtems_task_start(id, (rtems_task_entry)function, (rtems_task_argument)arg);
+
+ if (res != RTEMS_SUCCESSFUL) {
+ rtems_task_delete(id);
+ return 0;
+ }
+ return id;
+}
+
+err_t
+sys_mutex_new(sys_mutex_t *mutex)
+{
+ rtems_status_code ret = rtems_semaphore_create(
+ rtems_build_name('L', 'W', 'I', 'P'),
+ 1,
+ RTEMS_PRIORITY|RTEMS_BINARY_SEMAPHORE|RTEMS_INHERIT_PRIORITY|RTEMS_LOCAL,
+ 0,
+ &mutex->mutex
+ );
+
+ if (ret != RTEMS_SUCCESSFUL) {
+ mutex->mutex = RTEMS_ID_NONE;
+ return ret;
+ }
+ return ERR_OK;
+}
+/** Lock a mutex
+ * @param mutex the mutex to lock */
+void
+sys_mutex_lock(sys_mutex_t *mutex)
+{
+ rtems_semaphore_obtain(mutex->mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+}
+/** Unlock a mutex
+ * @param mutex the mutex to unlock */
+void
+sys_mutex_unlock(sys_mutex_t *mutex)
+{
+ rtems_semaphore_release(mutex->mutex);
+}
+/** Delete a semaphore
+ * @param mutex the mutex to delete */
+void
+sys_mutex_free(sys_mutex_t *mutex)
+{
+ rtems_semaphore_delete(mutex->mutex);
+}
+
+void
+sys_arch_delay(unsigned int timeout)
+{
+ rtems_interval tps = rtems_clock_get_ticks_per_second();
+ rtems_interval tick_timeout = (timeout * tps + 999) / 1000;
+
+ rtems_task_wake_after(tick_timeout);
+}
+
+/** Ticks/jiffies since power up. */
+uint32_t
+sys_jiffies(void)
+{
+ return rtems_clock_get_ticks_since_boot();
+}
+
+int
+sys_request_irq(unsigned int irqnum, sys_irq_handler_t handler,
+ unsigned long flags, const char *name, void *context)
+{
+ rtems_status_code res;
+
+ res = rtems_interrupt_handler_install(irqnum, name, flags,
+ handler, context);
+ return (res != RTEMS_SUCCESSFUL) ? -1 : 0;
+}
+
+sys_prot_t
+sys_arch_protect()
+{
+ sys_prot_t pval;
+
+ rtems_interrupt_disable(pval);
+ return pval;
+}
+
+void
+sys_arch_unprotect(sys_prot_t pval)
+{
+ rtems_interrupt_enable(pval);
+}
+err_t
+sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
+{
+ return sys_mbox_trypost(q, msg);
+}
+
diff --git a/uLan/ports/os/rtems/arch/sys_arch.h b/uLan/ports/os/rtems/arch/sys_arch.h
new file mode 100644
index 0000000..c89abd4
--- /dev/null
+++ b/uLan/ports/os/rtems/arch/sys_arch.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * This file is system adaptation of the lwIP TCP/IP stack
+ * by Adam Dunkels <adam@sics.se> for RTEMS system.
+ *
+ * Author: Premysl Houdek <houdepre@fel.cvut.cz>
+ * Mentor: Pavel Pisa <pisa@cmp.felk.cvut.cz>
+ * Industrial Informatics Group, FEE, Czech Technical University in Prague
+ *
+ */
+/*
+ * mapping of lwIP system dependencies to RTEMS system services and types.
+ * DETAILS: ./lwip/doc/sys_arch.txt
+ */
+#ifndef __ARCH_SYS_ARCH_H__
+#define __ARCH_SYS_ARCH_H__
+
+#include <rtems/rtems/sem.h>
+#include <rtems/rtems/intr.h>
+#include <rtems/score/cpu.h>
+#include <bsp/irq-generic.h>
+//#include "eth_lwip_default.h"
+
+/* Typedefs for the various port-specific types. */
+#if defined(NO_SYS) && NO_SYS
+ #error "RTEMS SYS_ARCH cannot be compiled in NO_SYS variant"
+#endif
+
+#define sys_arch_printk printk
+
+typedef struct {
+ rtems_id mailbox;
+ rtems_id sem;
+} port_mailbox_t;
+
+typedef struct {
+ rtems_id semaphore;
+} port_sem_t;
+
+typedef struct {
+ rtems_id mutex;
+} port_mutex_t;
+
+typedef port_mailbox_t sys_mbox_t;
+typedef port_sem_t sys_sem_t;
+typedef rtems_id sys_thread_t;
+typedef port_mutex_t sys_mutex_t;
+typedef rtems_interrupt_level sys_prot_t;
+
+void
+sys_arch_delay(unsigned int x);
+void
+sys_sem_signal_from_ISR(sys_sem_t *sem);
+
+typedef void sys_irqreturn_t;
+#define SYS_IRQ_NONE ((void)0)
+#define SYS_IRQ_HANDLED ((void)1)
+#define SYS_IRQ_RETVAL(x) (IRQ_HANDLED)
+typedef rtems_interrupt_handler sys_irq_handler_t;
+#define SYS_IRQ_HANDLER_FNC(M_fnc_name) \
+ sys_irqreturn_t M_fnc_name(void *__irq_handler_context)
+#define sys_irq_handler_get_context() (__irq_handler_context)
+
+int
+sys_request_irq(unsigned int irqnum, sys_irq_handler_t handler,
+ unsigned long flags, const char *name, void *context);
+
+static inline void
+sys_arch_mask_interrupt_source(unsigned int x)
+{
+ bsp_interrupt_vector_disable(x);
+}
+
+static inline void
+sys_arch_unmask_interrupt_source(unsigned int x)
+{
+ bsp_interrupt_vector_enable(x);
+}
+
+sys_prot_t sys_arch_protect();
+
+void sys_arch_unprotect(sys_prot_t pval);
+
+#endif /* __ARCH_SYS_ARCH_H__ */