3
0
mirror of https://github.com/XboxDev/nxdk.git synced 2026-02-04 15:05:30 +00:00

Add networking support

This commit adds networking support via pktdrv library, the LwIP stack,
and a driver that interfaces the two. To add networking support to your
project, specify NXDK_NET=y in your project Makefile.
This commit is contained in:
Matt Borgerson
2016-01-10 16:04:03 -07:00
parent df6d09357b
commit 104d8e39be
12 changed files with 2579 additions and 0 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "tools/extract-xiso"]
path = tools/extract-xiso
url = https://github.com/mborgerson/extract-xiso.git
[submodule "lib/net/lwip"]
path = lib/net/lwip
url = git://git.savannah.nongnu.org/lwip.git

View File

@ -45,6 +45,10 @@ ifneq ($(GEN_XISO),)
TARGET += $(GEN_XISO)
endif
ifneq ($(NXDK_NET),)
include $(NXDK_DIR)/lib/net/Makefile
endif
V = 0
VE_0 := @
VE_1 :=

18
lib/net/Makefile Normal file
View File

@ -0,0 +1,18 @@
# Include LWIP sources
LWIPDIR = $(NXDK_DIR)/lib/net/lwip/src
include $(LWIPDIR)/Filelists.mk
LWIPSRCS := $(COREFILES) \
$(CORE4FILES) \
$(NETIFFILES) \
$(APIFILES)
# Include driver sources
DRIVERSRCS := $(wildcard $(NXDK_DIR)/lib/net/pktdrv/*.c) \
$(wildcard $(NXDK_DIR)/lib/net/nforceif/src/*.c)
SRCS += $(LWIPSRCS) $(DRIVERSRCS)
# Add includes
CFLAGS += -I $(LWIPDIR)/include
CFLAGS += -I $(NXDK_DIR)/lib/net/nforceif/include
CFLAGS += -I $(NXDK_DIR)/lib/net/pktdrv

1
lib/net/lwip Submodule

Submodule lib/net/lwip added at b9d0d80946

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2015 Matt Borgerson
* 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: Adam Dunkels <adam@sics.se>
* Xbox Support: Matt Borgerson
*
*/
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H
/* Include some files for defining library routines */
#include <xboxrt/string.h>
#include <xboxrt/debug.h>
#include <hal/xbox.h>
#define printf debugPrint
#define fflush(...)
void abort(void);
//#define MEM_ALIGNMENT 4
/* Define platform endianness */
//#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
//#endif /* BYTE_ORDER */
/* Define generic types used in lwIP */
typedef unsigned char u8_t;
typedef signed char s8_t;
typedef unsigned short u16_t;
typedef signed short s16_t;
typedef unsigned int u32_t;
typedef signed int s32_t;
typedef unsigned long mem_ptr_t;
/* Define (sn)printf formatters for these lwIP types */
#define X8_F "02x"
#define U16_F "hu"
#define S16_F "hd"
#define X16_F "hx"
#define U32_F "u"
#define S32_F "d"
#define X32_F "x"
/* If only we could use C99 and get %zu */
#if defined(__x86_64__)
#define SZT_F "lu"
#else
#define SZT_F "u"
#endif
/* Compiler hints for packing structures */
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
/* Plaform specific diagnostic output */
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#ifdef LWIP_UNIX_EMPTY_ASSERT
#define LWIP_PLATFORM_ASSERT(x)
#else
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__); fflush(NULL); abort();} while(0)
#endif
#define LWIP_RAND() ((u32_t)XGetTickCount()) /* Not really random... */
struct sio_status_s;
typedef struct sio_status_s sio_status_t;
#define sio_fd_t sio_status_t*
#define __sio_fd_t_defined
#endif /* LWIP_ARCH_CC_H */

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2015 Matt Borgerson
* 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: Adam Dunkels <adam@sics.se>
* Xbox Support: Matt Borgerson
*
*/
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H
#include <usb/include/asm/errno.h>
#define SYS_MBOX_NULL NULL
#define SYS_SEM_NULL NULL
#if LWIP_DEBUG
extern unsigned char debug_flags;
#endif
typedef u32_t sys_prot_t;
struct sys_sem;
typedef struct sys_sem * sys_sem_t;
#define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL))
#define sys_sem_set_invalid(sem) do { if((sem) != NULL) { *(sem) = NULL; }}while(0)
/* let sys.h use binary semaphores for mutexes */
#define LWIP_COMPAT_MUTEX 1
struct sys_mbox;
typedef struct sys_mbox *sys_mbox_t;
#define sys_mbox_valid(mbox) (((mbox) != NULL) && (*(mbox) != NULL))
#define sys_mbox_set_invalid(mbox) do { if((mbox) != NULL) { *(mbox) = NULL; }}while(0)
struct sys_thread;
typedef struct sys_thread * sys_thread_t;
#endif /* LWIP_ARCH_SYS_ARCH_H */

View File

@ -0,0 +1,443 @@
/**
* @file
*
* lwIP Options Configuration
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* Copyright (c) 2015 Matt Borgerson
* 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: Adam Dunkels <adam@sics.se>
* Xbox Support: Matt Borgerson
*
*/
#ifndef LWIP_LWIPOPTS_H
#define LWIP_LWIPOPTS_H
#define LWIP_IPV4 1
#define LWIP_DEBUG 1
extern int errno;
/*
-----------------------------------------------
---------- Platform specific locking ----------
-----------------------------------------------
*/
/**
* NO_SYS==1: Provides VERY minimal functionality. Otherwise,
* use lwIP facilities.
*/
#define NO_SYS 0
/*
------------------------------------
---------- Memory options ----------
------------------------------------
*/
/**
* MEM_ALIGNMENT: should be set to the alignment of the CPU
* 4 byte alignment -> #define MEM_ALIGNMENT 4
* 2 byte alignment -> #define MEM_ALIGNMENT 2
*/
#define MEM_ALIGNMENT 1
/**
* MEM_SIZE: the size of the heap memory. If the application will send
* a lot of data that needs to be copied, this should be set high.
*/
#define MEM_SIZE 16000
/*
------------------------------------------------
---------- Internal Memory Pool Sizes ----------
------------------------------------------------
*/
/**
* MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF).
* If the application sends a lot of data out of ROM (or other static memory),
* this should be set high.
*/
#define MEMP_NUM_PBUF 128
/**
* MEMP_NUM_RAW_PCB: Number of raw connection PCBs
* (requires the LWIP_RAW option)
*/
#define MEMP_NUM_RAW_PCB 4
/**
* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
* per active UDP "connection".
* (requires the LWIP_UDP option)
*/
#define MEMP_NUM_UDP_PCB 4
/**
* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.
* (requires the LWIP_TCP option)
*/
#define MEMP_NUM_TCP_PCB 2
/**
* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.
* (requires the LWIP_TCP option)
*/
#define MEMP_NUM_TCP_PCB_LISTEN 8
/**
* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.
* (requires the LWIP_TCP option)
*/
#define MEMP_NUM_TCP_SEG 16
/**
* MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing
* packets (pbufs) that are waiting for an ARP request (to resolve
* their destination address) to finish.
* (requires the ARP_QUEUEING option)
*/
#define MEMP_NUM_ARP_QUEUE 2
/**
* MEMP_NUM_SYS_TIMEOUT: the number of simultaneously active timeouts.
* The default number of timeouts is calculated here for all enabled modules.
* The formula expects settings to be either '0' or '1'.
*
* To this default value, 1 was added for the snmp_increment timer.
*/
#define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) + 1
/**
* MEMP_NUM_NETBUF: the number of struct netbufs.
* (only needed if you use the sequential API, like api_lib.c)
*/
#define MEMP_NUM_NETBUF 8
/**
* MEMP_NUM_NETCONN: the number of struct netconns.
* (only needed if you use the sequential API, like api_lib.c)
*/
#define MEMP_NUM_NETCONN 8
/**
* MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used
* for callback/timeout API communication.
* (only needed if you use tcpip.c)
*/
#define MEMP_NUM_TCPIP_MSG_API 8
/**
* MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used
* for incoming packets.
* (only needed if you use tcpip.c)
*/
#define MEMP_NUM_TCPIP_MSG_INPKT 2
/**
* PBUF_POOL_SIZE: the number of buffers in the pbuf pool.
*/
#define PBUF_POOL_SIZE 32
/*
---------------------------------
---------- ARP options ----------
---------------------------------
*/
/**
* LWIP_ARP==1: Enable ARP functionality.
*/
#define LWIP_ARP 1
/*
--------------------------------
---------- IP options ----------
--------------------------------
*/
/**
* IP_FORWARD==1: Enables the ability to forward IP packets across network
* interfaces. If you are going to run lwIP on a device with only one network
* interface, define this to 0.
*/
#define IP_FORWARD 0
/**
* IP_OPTIONS: Defines the behavior for IP options.
* IP_OPTIONS==0_ALLOWED: All packets with IP options are dropped.
* IP_OPTIONS==1_ALLOWED: IP options are allowed (but not parsed).
*/
#define IP_OPTIONS_ALLOWED 1
/**
* IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that
* this option does not affect outgoing packet sizes, which can be controlled
* via IP_FRAG.
*/
#define IP_REASSEMBLY 1
/**
* IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note
* that this option does not affect incoming packet sizes, which can be
* controlled via IP_REASSEMBLY.
*/
#define IP_FRAG 1
/**
* IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)
* a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived
* in this time, the whole packet is discarded.
*/
#define IP_REASS_MAXAGE 3
/**
* IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.
* Since the received pbufs are enqueued, be sure to configure
* PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive
* packets even if the maximum amount of fragments is enqueued for reassembly!
*/
#define IP_REASS_MAX_PBUFS 10
/**
* IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP
* fragmentation. Otherwise pbufs are allocated and reference the original
* packet data to be fragmented.
*/
#define IP_FRAG_USES_STATIC_BUF 0
/**
* IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.
*/
#define IP_DEFAULT_TTL 255
/*
----------------------------------
---------- ICMP options ----------
----------------------------------
*/
/**
* LWIP_ICMP==1: Enable ICMP module inside the IP stack.
* Be careful, disable that make your product non-compliant to RFC1122
*/
#define LWIP_ICMP 1
/**
* ICMP_TTL: Default value for Time-To-Live used by ICMP packets.
*/
#define ICMP_TTL (IP_DEFAULT_TTL)
/*
---------------------------------
---------- RAW options ----------
---------------------------------
*/
/**
* LWIP_RAW==1: Enable application layer to hook into the IP layer itself.
*/
#define LWIP_RAW 1
/*
----------------------------------
---------- DHCP options ----------
----------------------------------
*/
/**
* LWIP_DHCP==1: Enable DHCP module.
*/
#define LWIP_DHCP 1
/*
------------------------------------
---------- AUTOIP options ----------
------------------------------------
*/
/**
* LWIP_AUTOIP==1: Enable AUTOIP module.
*/
#define LWIP_AUTOIP 0
/*
----------------------------------
---------- SNMP options ----------
----------------------------------
*/
/**
* LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP
* transport.
*/
#define LWIP_SNMP 1
#define LWIP_MIB2_CALLBACKS 0
#define MIB2_STATS 1
/*
----------------------------------
---------- IGMP options ----------
----------------------------------
*/
/**
* LWIP_IGMP==1: Turn on IGMP module.
*/
#define LWIP_IGMP 0
/*
----------------------------------
---------- DNS options -----------
----------------------------------
*/
/**
* LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS
* transport.
*/
#define LWIP_DNS 0
/*
---------------------------------
---------- UDP options ----------
---------------------------------
*/
/**
* LWIP_UDP==1: Turn on UDP.
*/
#define LWIP_UDP 1
/**
* LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP)
*/
#define LWIP_UDPLITE 0
/**
* UDP_TTL: Default Time-To-Live value.
*/
#define UDP_TTL (IP_DEFAULT_TTL)
/*
---------------------------------
---------- TCP options ----------
---------------------------------
*/
/**
* LWIP_TCP==1: Turn on TCP.
*/
#define LWIP_TCP 1
/*
----------------------------------
---------- Pbuf options ----------
----------------------------------
*/
/**
* PBUF_LINK_HLEN: the number of bytes that should be allocated for a
* link level header. The default is 14, the standard value for
* Ethernet.
*/
#define PBUF_LINK_HLEN 16
/*
------------------------------------
---------- LOOPIF options ----------
------------------------------------
*/
/**
* LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c
*/
#define LWIP_HAVE_LOOPIF 0
/*
----------------------------------------------
---------- Sequential layer options ----------
----------------------------------------------
*/
/**
* LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
*/
#define LWIP_NETCONN 1
/*
------------------------------------
---------- Socket options ----------
------------------------------------
*/
/**
* LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
*/
#define LWIP_SOCKET 1
/*
----------------------------------------
---------- Statistics options ----------
----------------------------------------
*/
/**
* LWIP_STATS==1: Enable statistics collection in lwip_stats.
*/
#define LWIP_STATS 1
/*
---------------------------------------
---------- Debugging options ----------
---------------------------------------
*/
#define TAPIF_DEBUG LWIP_DBG_ON
#define TUNIF_DEBUG LWIP_DBG_OFF
#define UNIXIF_DEBUG LWIP_DBG_OFF
#define DELIF_DEBUG LWIP_DBG_OFF
#define SIO_FIFO_DEBUG LWIP_DBG_OFF
#define TCPDUMP_DEBUG LWIP_DBG_ON
#define API_LIB_DEBUG LWIP_DBG_ON
#define API_MSG_DEBUG LWIP_DBG_ON
#define TCPIP_DEBUG LWIP_DBG_ON
#define NETIF_DEBUG LWIP_DBG_ON
#define SOCKETS_DEBUG LWIP_DBG_ON
#define DEMO_DEBUG LWIP_DBG_ON
#define IP_DEBUG LWIP_DBG_ON
#define IP_REASS_DEBUG LWIP_DBG_ON
#define RAW_DEBUG LWIP_DBG_ON
#define ICMP_DEBUG LWIP_DBG_ON
#define UDP_DEBUG LWIP_DBG_ON
#define TCP_DEBUG LWIP_DBG_ON
#define TCP_INPUT_DEBUG LWIP_DBG_ON
#define TCP_OUTPUT_DEBUG LWIP_DBG_ON
#define TCP_RTO_DEBUG LWIP_DBG_ON
#define TCP_CWND_DEBUG LWIP_DBG_ON
#define TCP_WND_DEBUG LWIP_DBG_ON
#define TCP_FR_DEBUG LWIP_DBG_ON
#define TCP_QLEN_DEBUG LWIP_DBG_ON
#define TCP_RST_DEBUG LWIP_DBG_ON
extern unsigned char debug_flags;
#define LWIP_DBG_TYPES_ON debug_flags
#define ETHARP_DEBUG LWIP_DBG_ON
#endif /* LWIP_LWIPOPTS_H */

View File

@ -0,0 +1,370 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* Copyright (c) 2015 Matt Borgerson
*
* 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: Adam Dunkels <adam@sics.se>
* Xbox Support: Matt Borgerson
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/ethip6.h"
#include "netif/etharp.h"
#include "netif/ppp/pppoe.h"
/* Define those to better describe your network interface. */
#define IFNAME0 'x'
#define IFNAME1 'b'
#include "../../pktdrv/pktdrv.h"
#define LINK_SPEED_OF_YOUR_NETIF_IN_BPS 100*1000*1000 /* 100 Mbps */
#include <xboxkrnl/xboxkrnl.h>
static unsigned int g_rx_buffer_packetsize;
static unsigned char *g_rx_buffer, *g_tx_buffer;
extern struct netif *g_pnetif;
/**
* Helper struct to hold private data used to operate your ethernet interface.
* Keeping the ethernet address of the MAC in this struct is not necessary
* as it is already kept in the struct netif.
* But this is only an example, anyway...
*/
struct nforceif {
struct eth_addr *ethaddr;
/* Add whatever per-interface state that is needed here. */
};
/* Forward declarations. */
void nforceif_input(struct netif *netif);
int Pktdrv_Callback(unsigned char *packetaddr, unsigned int size)
{
g_rx_buffer_packetsize=size;
memcpy(g_rx_buffer,packetaddr,g_rx_buffer_packetsize);
nforceif_input(g_pnetif);
return 1;
}
/**
* In this function, the hardware should be initialized.
* Called from nforceif_init().
*
* @param netif the already initialized lwip network interface structure
* for this nforceif
*/
static void
low_level_init(struct netif *netif)
{
struct nforceif *nforceif = netif->state;
if (!Pktdrv_Init())
{
debugPrint("Failed to initialize packet driver!\n");
abort();
}
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
Pktdrv_GetEthernetAddr(netif->hwaddr);
/* maximum transfer unit */
netif->mtu = 1500;
/* 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;
#if LWIP_IPV6 && LWIP_IPV6_MLD
/*
* For hardware/netifs that implement MAC filtering.
* All-nodes link-local is handled by default, so we must let the hardware know
* to allow multicast packets in.
* Should set mld_mac_filter previously. */
if (netif->mld_mac_filter != NULL) {
ip6_addr_t ip6_allnodes_ll;
ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll);
netif->mld_mac_filter(netif, &ip6_allnodes_ll, MLD6_ADD_MAC_FILTER);
}
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/* Do whatever else is needed to initialize interface. */
g_rx_buffer=(unsigned char *)MmAllocateContiguousMemoryEx(
1520,
0, //lowest acceptable
0xFFFFFFFF, //highest acceptable
0, //no need to align to specific boundaries multiple
4); //non cached, non ordered
g_tx_buffer=(unsigned char *)MmAllocateContiguousMemoryEx(
1520,
0, //lowest acceptable
0xFFFFFFFF, //highest acceptable
0, //no need to align to specific boundaries multiple
4); //non cached, non ordered
if (!g_rx_buffer || !g_tx_buffer)
{
debugPrint("Failed to allocate packet buffer!\n");
abort();
}
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this nforceif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become available since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
struct nforceif *nforceif = netif->state;
struct pbuf *q;
unsigned long buf_pos = 0;
//initiate transfer();
while (Pktdrv_GetQueuedTxPkts()>0) /* spin */; // FIXME!
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
for (q = p; q != NULL; q = q->next) {
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
//send data from(q->payload, q->len);
memcpy(g_tx_buffer+buf_pos, q->payload, q->len);
buf_pos += q->len;
}
//signal that packet should be sent();
Pktdrv_SendPacket(g_tx_buffer, buf_pos);
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.xmit);
return ERR_OK;
}
/**
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
* @param netif the lwip network interface structure for this nforceif
* @return a pbuf filled with the received packet (including MAC header)
* NULL on memory error
*/
static struct pbuf *
low_level_input(struct netif *netif)
{
struct nforceif *nforceif = netif->state;
struct pbuf *p, *q;
u16_t len;
unsigned long buf_pos = 0;
/* Obtain the size of the packet and put it into the "len"
variable. */
len = g_rx_buffer_packetsize;
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
/* We allocate a pbuf chain of pbufs from the pool. */
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
if (p != NULL) {
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
/* We iterate over the pbuf chain until we have read the entire
* packet into the pbuf. */
for (q = p; (q != NULL) && (buf_pos < len); q = q->next) {
/* Read enough bytes to fill this pbuf in the chain. The
* available data in the pbuf is given by the q->len
* variable.
* This does not necessarily have to be a memcpy, you can also preallocate
* pbufs for a DMA-enabled MAC and after receiving truncate it to the
* actually received size. In this case, ensure the tot_len member of the
* pbuf is the sum of the chained pbuf len members.
*/
// read data into(q->payload, q->len);
memcpy(q->payload, g_rx_buffer+buf_pos, q->len);
buf_pos += q->len;
}
// acknowledge that packet has been read();
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
LINK_STATS_INC(link.recv);
} else {
// drop packet();
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
}
return p;
}
/**
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this nforceif
*/
void // FIXME make static
nforceif_input(struct netif *netif)
{
struct nforceif *nforceif;
struct eth_hdr *ethhdr;
struct pbuf *p;
nforceif = netif->state;
/* move received packet into a new pbuf */
p = low_level_input(netif);
/* no packet could be read, silently ignore this */
if (p == NULL) return;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_IPV6:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif)!=ERR_OK)
{ LWIP_DEBUGF(NETIF_DEBUG, ("nforceif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
p = NULL;
break;
}
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this nforceif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t
nforceif_init(struct netif *netif)
{
struct nforceif *nforceif;
LWIP_ASSERT("netif != NULL", (netif != NULL));
nforceif = mem_malloc(sizeof(struct nforceif));
if (nforceif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("nforceif_init: out of memory\n"));
return ERR_MEM;
}
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
netif->hostname = "lwip";
#endif /* LWIP_NETIF_HOSTNAME */
/*
* 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.
*/
MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
netif->state = nforceif;
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your 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;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
nforceif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}

View File

@ -0,0 +1,431 @@
/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* Copyright (c) 2015 Matt Borgerson
*
* 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: Adam Dunkels <adam@sics.se>
* Xbox Support: Matt Borgerson
*
*/
#include "lwip/debug.h"
#include "lwip/sys.h"
#include "lwip/opt.h"
#include "lwip/stats.h"
#include <hal/xbox.h>
#if !NO_SYS
#include "xboxkrnl/nt.h"
#include <xboxrt/stdlib.h>
static struct sys_sem *sys_sem_new_internal(u8_t count);
static void sys_sem_free_internal(struct sys_sem *sem);
static struct sys_thread *threads = NULL;
struct sys_mbox_msg {
struct sys_mbox_msg *next;
void *msg;
};
#define SYS_MBOX_SIZE 128
struct sys_mbox {
int first, last;
void *msgs[SYS_MBOX_SIZE];
struct sys_sem *not_empty;
struct sys_sem *not_full;
struct sys_sem *mutex;
int wait_send;
};
struct sys_sem {
unsigned int c;
HANDLE handle;
};
struct sys_thread {
struct sys_thread *next;
int handle;
};
#endif /* !NO_SYS */
#if LWIP_DEBUG
unsigned char debug_flags;
#endif
int errno;
u32_t
sys_now(void)
{
unsigned int now, freq = 733000;
/* Read TSC into EDX:EAX, then divide TSC by processor freq / 1000 to
* get elapsed milliseconds since reset (roughly).
*/
asm __volatile__ ("rdtsc; divl %1"
: "=a" (now)
: "r" (freq)
: "%eax", "%edx");
return now;
}
void
sys_init(void)
{
}
#if 0
u32_t
sys_jiffies(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000L + ts.tv_nsec;
}
#endif
void abort(void)
{
debugPrint("Aborted!\n");
XSleep(5000);
XReboot();
}
#if !NO_SYS
sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
{
struct sys_thread *st = NULL;
LWIP_UNUSED_ARG(name);
LWIP_UNUSED_ARG(stacksize);
LWIP_UNUSED_ARG(prio);
st = (struct sys_thread *)malloc(sizeof(struct sys_thread));
if (NULL == st) {
abort();
}
st->handle = XCreateThread((void *)function, arg, NULL);
return st;
}
err_t
sys_mbox_new(struct sys_mbox **mb, int size)
{
struct sys_mbox *mbox;
LWIP_UNUSED_ARG(size);
mbox = (struct sys_mbox *)malloc(sizeof(struct sys_mbox));
if (mbox == NULL) {
return ERR_MEM;
}
mbox->first = mbox->last = 0;
mbox->not_empty = sys_sem_new_internal(0);
mbox->not_full = sys_sem_new_internal(0);
mbox->mutex = sys_sem_new_internal(1);
mbox->wait_send = 0;
SYS_STATS_INC_USED(mbox);
*mb = mbox;
return ERR_OK;
}
void
sys_mbox_free(struct sys_mbox **mb)
{
if ((mb != NULL) && (*mb != SYS_MBOX_NULL)) {
struct sys_mbox *mbox = *mb;
SYS_STATS_DEC(mbox.used);
sys_arch_sem_wait(&mbox->mutex, 0);
sys_sem_free_internal(mbox->not_empty);
sys_sem_free_internal(mbox->not_full);
sys_sem_free_internal(mbox->mutex);
mbox->not_empty = mbox->not_full = mbox->mutex = NULL;
/* LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */
free(mbox);
}
}
err_t
sys_mbox_trypost(struct sys_mbox **mb, void *msg)
{
u8_t first;
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
sys_arch_sem_wait(&mbox->mutex, 0);
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n",
(void *)mbox, (void *)msg));
if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
sys_sem_signal(&mbox->mutex);
return ERR_MEM;
}
mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
if (mbox->last == mbox->first) {
first = 1;
} else {
first = 0;
}
mbox->last++;
if (first) {
sys_sem_signal(&mbox->not_empty);
}
sys_sem_signal(&mbox->mutex);
return ERR_OK;
}
void
sys_mbox_post(struct sys_mbox **mb, void *msg)
{
u8_t first;
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
sys_arch_sem_wait(&mbox->mutex, 0);
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg));
while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) {
mbox->wait_send++;
sys_sem_signal(&mbox->mutex);
sys_arch_sem_wait(&mbox->not_full, 0);
sys_arch_sem_wait(&mbox->mutex, 0);
mbox->wait_send--;
}
mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg;
if (mbox->last == mbox->first) {
first = 1;
} else {
first = 0;
}
mbox->last++;
if (first) {
sys_sem_signal(&mbox->not_empty);
}
sys_sem_signal(&mbox->mutex);
}
u32_t
sys_arch_mbox_tryfetch(struct sys_mbox **mb, void **msg)
{
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
sys_arch_sem_wait(&mbox->mutex, 0);
if (mbox->first == mbox->last) {
sys_sem_signal(&mbox->mutex);
return SYS_MBOX_EMPTY;
}
if (msg != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg));
*msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
}
else{
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox));
}
mbox->first++;
if (mbox->wait_send) {
sys_sem_signal(&mbox->not_full);
}
sys_sem_signal(&mbox->mutex);
return 0;
}
u32_t
sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, u32_t timeout)
{
u32_t time_needed = 0;
struct sys_mbox *mbox;
LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL));
mbox = *mb;
/* The mutex lock is quick so we don't bother with the timeout
stuff here. */
sys_arch_sem_wait(&mbox->mutex, 0);
while (mbox->first == mbox->last) {
sys_sem_signal(&mbox->mutex);
/* We block while waiting for a mail to arrive in the mailbox. We
must be prepared to timeout. */
if (timeout != 0) {
time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout);
if (time_needed == SYS_ARCH_TIMEOUT) {
return SYS_ARCH_TIMEOUT;
}
} else {
sys_arch_sem_wait(&mbox->not_empty, 0);
}
sys_arch_sem_wait(&mbox->mutex, 0);
}
if (msg != NULL) {
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg));
*msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE];
}
else{
LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox));
}
mbox->first++;
if (mbox->wait_send) {
sys_sem_signal(&mbox->not_full);
}
sys_sem_signal(&mbox->mutex);
return time_needed;
}
static struct sys_sem *
sys_sem_new_internal(u8_t count)
{
struct sys_sem *sem;
sem = (struct sys_sem *)malloc(sizeof(struct sys_sem));
if (sem != NULL) {
sem->c = count;
NtCreateSemaphore(&(sem->handle), NULL, 1, 1);
}
return sem;
}
err_t
sys_sem_new(struct sys_sem **sem, u8_t count)
{
SYS_STATS_INC_USED(sem);
*sem = sys_sem_new_internal(count);
if (*sem == NULL) {
return ERR_MEM;
}
return ERR_OK;
}
u32_t
sys_arch_sem_wait(struct sys_sem **s, u32_t timeout)
{
u32_t start, time_needed = 0;
struct sys_sem *sem;
LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
sem = *s;
int done;
start = sys_now();
for (done=0; !done; )
{
NtWaitForSingleObject(sem->handle, FALSE, NULL);
if (sem->c > 0)
{
sem->c -= 1;
done = 1;
}
NtReleaseSemaphore(sem->handle, 1, NULL);
if (timeout > 0)
{
time_needed = sys_now()-start;
if (time_needed >= timeout) return SYS_ARCH_TIMEOUT;
}
}
return (u32_t)time_needed;
}
void
sys_sem_signal(struct sys_sem **s)
{
struct sys_sem *sem;
LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL));
sem = *s;
NtWaitForSingleObject(sem->handle, FALSE, NULL);
sem->c++;
if (sem->c > 1) {
sem->c = 1;
}
NtReleaseSemaphore(sem->handle, 1, NULL);
}
static void
sys_sem_free_internal(struct sys_sem *sem)
{
// FIXME! This will leak.
// NTSTATUS status = NtClose((void*)sem->handle);
// if (NT_SUCCESS(status)) {
// abort();
// }
free(sem);
}
void
sys_sem_free(struct sys_sem **sem)
{
if ((sem != NULL) && (*sem != SYS_SEM_NULL)) {
SYS_STATS_DEC(sem.used);
sys_sem_free_internal(*sem);
}
}
#endif /* !NO_SYS */

166
lib/net/pktdrv/license.txt Normal file
View File

@ -0,0 +1,166 @@
The Academic Free License
v. 2.0
This Academic Free License (the "License") applies to any original work
of authorship (the "Original Work") whose owner (the "Licensor") has
placed the following notice immediately following the copyright notice
for the Original Work:
*Licensed under the Academic Free License version 2.0*
1) *Grant of Copyright License.* Licensor hereby grants You a
world-wide, royalty-free, non-exclusive, perpetual, sublicenseable
license to do the following:
a) to reproduce the Original Work in copies;
b) to prepare derivative works ("Derivative Works") based upon the
Original Work;
c) to distribute copies of the Original Work and Derivative Works to
the public;
d) to perform the Original Work publicly; and
e) to display the Original Work publicly.
2) *Grant of Patent License.* Licensor hereby grants You a world-wide,
royalty-free, non-exclusive, perpetual, sublicenseable license, under
patent claims owned or controlled by the Licensor that are embodied in
the Original Work as furnished by the Licensor, to make, use, sell and
offer for sale the Original Work and Derivative Works.
3) *Grant of Source Code License.* The term "Source Code" means the
preferred form of the Original Work for making modifications to it and
all available documentation describing how to modify the Original Work.
Licensor hereby agrees to provide a machine-readable copy of the Source
Code of the Original Work along with each copy of the Original Work that
Licensor distributes. Licensor reserves the right to satisfy this
obligation by placing a machine-readable copy of the Source Code in an
information repository reasonably calculated to permit inexpensive and
convenient access by You for as long as Licensor continues to distribute
the Original Work, and by publishing the address of that information
repository in a notice immediately following the copyright notice that
applies to the Original Work.
4) *Exclusions From License Grant. *Neither the names of Licensor, nor
the names of any contributors to the Original Work, nor any of their
trademarks or service marks, may be used to endorse or promote products
derived from this Original Work without express prior written permission
of the Licensor. Nothing in this License shall be deemed to grant any
rights to trademarks, copyrights, patents, trade secrets or any other
intellectual property of Licensor except as expressly stated herein. No
patent license is granted to make, use, sell or offer to sell
embodiments of any patent claims other than the licensed claims defined
in Section 2. No right is granted to the trademarks of Licensor even if
such marks are included in the Original Work. Nothing in this License
shall be interpreted to prohibit Licensor from licensing under different
terms from this License any Original Work that Licensor otherwise would
have a right to license.
5) This section intentionally omitted.
6) *Attribution Rights.* You must retain, in the Source Code of any
Derivative Works that You create, all copyright, patent or trademark
notices from the Source Code of the Original Work, as well as any
notices of licensing and any descriptive text identified therein as an
"Attribution Notice." You must cause the Source Code for any Derivative
Works that You create to carry a prominent Attribution Notice reasonably
calculated to inform recipients that You have modified the Original Work.
7) *Warranty of Provenance and Disclaimer of Warranty.* Licensor
warrants that the copyright in and to the Original Work and the patent
rights granted herein by Licensor are owned by the Licensor or are
sublicensed to You under the terms of this License with the permission
of the contributor(s) of those copyrights and patent rights. Except as
expressly stated in the immediately proceeding sentence, the Original
Work is provided under this License on an "AS IS" BASIS and WITHOUT
WARRANTY, either express or implied, including, without limitation, the
warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL
WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential
part of this License. No license to Original Work is granted hereunder
except under this disclaimer.
8) *Limitation of Liability.* Under no circumstances and under no legal
theory, whether in tort (including negligence), contract, or otherwise,
shall the Licensor be liable to any person for any direct, indirect,
special, incidental, or consequential damages of any character arising
as a result of this License or the use of the Original Work including,
without limitation, damages for loss of goodwill, work stoppage,
computer failure or malfunction, or any and all other commercial damages
or losses. This limitation of liability shall not apply to liability for
death or personal injury resulting from Licensor's negligence to the
extent applicable law prohibits such limitation. Some jurisdictions do
not allow the exclusion or limitation of incidental or consequential
damages, so this exclusion and limitation may not apply to You.
9) *Acceptance and Termination.* If You distribute copies of the
Original Work or a Derivative Work, You must make a reasonable effort
under the circumstances to obtain the express assent of recipients to
the terms of this License. Nothing else but this License (or another
written agreement between Licensor and You) grants You permission to
create Derivative Works based upon the Original Work or to exercise any
of the rights granted in Section 1 herein, and any attempt to do so
except under the terms of this License (or another written agreement
between Licensor and You) is expressly prohibited by U.S. copyright law,
the equivalent laws of other countries, and by international treaty.
Therefore, by exercising any of the rights granted to You in Section 1
herein, You indicate Your acceptance of this License and all of its
terms and conditions.
10) *Termination for Patent Action.* This License shall terminate
automatically and You may no longer exercise any of the rights granted
to You by this License as of the date You commence an action, including
a cross-claim or counterclaim, for patent infringement (i) against
Licensor with respect to a patent applicable to software or (ii) against
any entity with respect to a patent applicable to the Original Work (but
excluding combinations of the Original Work with other software or
hardware).
11) *Jurisdiction, Venue and Governing Law.* Any action or suit relating
to this License may be brought only in the courts of a jurisdiction
wherein the Licensor resides or in which Licensor conducts its primary
business, and under the laws of that jurisdiction excluding its
conflict-of-law provisions. The application of the United Nations
Convention on Contracts for the International Sale of Goods is expressly
excluded. Any use of the Original Work outside the scope of this License
or after its termination shall be subject to the requirements and
penalties of the U.S. Copyright Act, 17 U.S.C. - 101 et seq., the
equivalent laws of other countries, and international treaty. This
section shall survive the termination of this License.
12) *Attorneys Fees.* In any action to enforce the terms of this License
or seeking damages relating thereto, the prevailing party shall be
entitled to recover its costs and expenses, including, without
limitation, reasonable attorneys' fees and costs incurred in connection
with such action, including any appeal of such action. This section
shall survive the termination of this License.
13) *Miscellaneous.* This License represents the complete agreement
concerning the subject matter hereof. If any provision of this License
is held to be unenforceable, such provision shall be reformed only to
the extent necessary to make it enforceable.
14) *Definition of "You" in This License.* "You" throughout this
License, whether in upper or lower case, means an individual or a legal
entity exercising rights under, and complying with all of the terms of,
this License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with you. For
purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether
by contract or otherwise, or (ii) ownership of fifty percent (50%) or
more of the outstanding shares, or (iii) beneficial ownership of such
entity.
15) *Right to Use.* You may use the Original Work in all ways not
otherwise restricted or conditioned by this License or by law, and
Licensor promises not to interfere with or be responsible for such uses
by You.
This license is Copyright (C) 2003 Lawrence E. Rosen. All rights
reserved. Permission is hereby granted to copy and distribute this
license without modification. This license may not be modified without
the express written permission of its copyright owner.

965
lib/net/pktdrv/pktdrv.c Normal file
View File

@ -0,0 +1,965 @@
//XBOX low level network interface driver (packet driver)
//=======================================================
//Minimum capabilites : send and receive ethernet packets
//Based on forcedeth Linux nForce driver
//Ring of buffers for received packets is handled by driver.
//Ring of buffers for sent packets must be handled by yourself.
//Driver will only handle the ring of descriptors for them.
//i.e Call Pktdrv_SendPacket with a buffer address taken among
//your ring of n buffers in a circular way and always verify
//that Pktdrv_GetQueuedTxPkts()<n before calling Pktdrv_SendPacket
//In most case, people will just handle n=1 buffer for sending.
//Buffers must be contiguous memory buffers (use Mm fonction).
//int Pktdrv_Callback(unsigned char *packetaddr, unsigned int packetsize)
//has to be defined in your code. Check frequently the number of pkts
//your callback accepted with Pktdrv_ReceivePackets() to trigger calls.
//(NBBUFF pkts will be safely stored until you decide to check for them)
//return 0 if you couldn't receive packet (will be kept for next time).
//In MyPktdrvDpc you can uncomment a line in order to have your callback
//called as soon as a packet arrives (your callback will be called by
//a DPC which means you don't need to be reentrant but you shouldn't
//mess with fpu unless you save and restore fpu processor state)
#include <hal/xbox.h>
#include <xboxrt/debug.h>
#include <xboxkrnl/xboxkrnl.h>
#include "string.h"
#include "stdio.h"
#include <stdlib.h>
//#include <memory.h>
#include "pktdrv.h"
#define DISPLAYMSG
//Defines number of Rx & Tx descriptors, and number of buffers -ring- for received pkts
#define NBBUFF 32
extern unsigned long times(void *);
//temporary dirty interface
extern int something_to_send;
extern unsigned char *packet_to_send;
extern unsigned int size_of_packet_to_send;
extern int Pktdrv_Callback(unsigned char *packetaddr, unsigned int packetsize);
#define MIN(a,b) (((a)<(b))?(a):(b))
struct s_MyStructures {
char MyContext[1];
unsigned char NbrRxBuffersWithoutCheck;
unsigned char Ethaddr[6];
unsigned char Ethaddr2[6];
unsigned char Ethaddr_reversed[6];
KDPC MyPktdrvDpcObject;
ULONG PktdrvIsrCounter;
KIRQL IrqLevel;
ULONG Vector;
ULONG Speed;
ULONG OldPhyState;
ULONG PhysicalMinusVirtual; // = buffers_physaddr - buffers_addrs;
ULONG NbrRxBuffers;
ULONG RxBufferDesc; //= buffers_addr + 2048;
ULONG RxBufferTail; //= buffers_addr + 2048 + g_s->NbrRxBuffers * 8 - 8;
ULONG RxBufferNext; //= buffers_addr + 2048; //Point to next incoming packet entry
ULONG NbrTxBuffers;
ULONG TxBufferDesc; //= buffers_addr;
ULONG TxBufferLast; //= buffers_addr; //Points to last sent packet(s) to check
ULONG TxBufferNext; //= buffers_addr; //Points to next packet to send entry
ULONG TxBufferTail; //= buffers_addr + 8 * g_s->NbrTxBuffers - 8;
ULONG QueuedTxPkts;
};
static int g_running=0;
static struct s_MyStructures *g_s;
static KINTERRUPT s_MyInterruptObject;
//Types and descriptions coming from
//- ntddk.h (WinXP SP1 DDK)
//- winddk.h (Reactos source)
//- forcedeth.c (Linux NVidia nForce driver)
/*
* Hardware registers:
*/
enum {
NvRegIrqStatus = 0x000,
#define NVREG_IRQSTAT_BIT0EVENT 0x002
#define NVREG_IRQSTAT_BIT1EVENT 0x004
#define NVREG_IRQSTAT_BIT2EVENT 0x008
#define NVREG_IRQSTAT_MIIEVENT 0x040
#define NVREG_IRQSTAT_UNKEVENT 0x080
#define NVREG_IRQSTAT_MASK 0x1FF
NvRegIrqMask = 0x004,
#define NVREG_IRQ_RX_ERROR 0x0001
#define NVREG_IRQ_RX 0x0002
#define NVREG_IRQ_RX_NOBUF 0x0004
#define NVREG_IRQ_TX_ERROR 0x0008
#define NVREG_IRQ_TX_OK 0x0010
#define NVREG_IRQ_TIMER 0x0020
#define NVREG_IRQ_LINK 0x0040
#define NVREG_IRQ_RX_FORCED 0x0080
#define NVREG_IRQ_TX_FORCED 0x0100
#define NVREG_IRQMASK_THROUGHPUT 0x00DF
#define NVREG_IRQMASK_CPU 0x0040
#define NVREG_IRQ_TX_ALL 0x0118
//=(NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED)
#define NVREG_IRQ_RX_ALL 0x0087
//=(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED)
#define NVREG_IRQ_OTHER 0x0060
//=(NVREG_IRQ_TIMER|NVREG_IRQ_LINK)
#define NVREG_IRQ_UNKNOWN 0x01FF
//=(~
// (
// NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|
// NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|
// NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED|NVREG_IRQ_TX_FORCED
// )
// )
NvRegUnknownSetupReg6 = 0x008,
#define NVREG_UNKSETUP6_VAL 3
/*
* NVREG_POLL_DEFAULT is the interval length of the timer source on the Pktdrv
* NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
*/
NvRegPollingInterval = 0x00c,
#define NVREG_POLL_DEFAULT_THROUGHPUT 970
#define NVREG_POLL_DEFAULT_CPU 013
NvRegMSIMap0 = 0x020,
NvRegMSIMap1 = 0x024,
NvRegMSIIrqMask = 0x030,
#define NVREG_MSI_VECTOR_0_ENABLED 0x001
NvRegMacReset = 0x03c,
#define NVREG_MAC_RESET_ASSERT 0x0F3
NvRegDuplexMode = 0x080,
#define NVREG_DUPLEX_MODE_HDFLAG 0x00000002
#define NVREG_DUPLEX_MODE_FORCEF 0x003B0F3C
#define NVREG_DUPLEX_MODE_FORCEH 0x003B0F3E
#define NVREG_DUPLEX_MODE_FDMASK 0xFFFFFFFD
NvRegTransmitterControl = 0x084,
#define NVREG_SendCTL_START 0x01
NvRegTransmitterStatus = 0x088,
#define NVREG_SendSTAT_BUSY 0x01
NvRegPacketFilterFlags = 0x08c,
#define NVREG_PFF_ALWAYS 0x7F0008
#define NVREG_PFF_PROMISC 0x000080
#define NVREG_PFF_MYADDR 0x000020
#define NVREG_PFF_ALWAYS_MYADDR 0x7F0020
NvRegOffloadConfig = 0x090,
#define NVREG_OFFLOAD_HOMEPHY 0x601
#define NVREG_OFFLOAD_NORMAL 0x5EE
NvRegReceiverControl = 0x094,
#define NVREG_RCVCTL_START 0x01
NvRegReceiverStatus = 0x098,
#define NVREG_RCVSTAT_BUSY 0x01
NvRegRandomSeed = 0x09c,
#define NVREG_RNDSEED_MASK 0x00FF
#define NVREG_RNDSEED_FORCE 0x7F00
#define NVREG_RNDSEED_FORCE2 0x2D00
#define NVREG_RNDSEED_FORCE3 0x7400
NvRegUnknownSetupReg1 = 0x0A0,
#define NVREG_UNKSETUP1_VAL 0x16070F
NvRegUnknownSetupReg2 = 0x0A4,
#define NVREG_UNKSETUP2_VAL 0x16
NvRegMacAddrA = 0x0A8,
NvRegMacAddrB = 0x0AC,
NvRegMulticastAddrA = 0x0B0,
#define NVREG_MCASTADDRA_FORCE 0x01
NvRegMulticastAddrB = 0x0B4,
NvRegMulticastMaskA = 0x0B8,
NvRegMulticastMaskB = 0x0BC,
NvRegPhyInterface = 0x0C0,
#define PHY_RGMII 0x10000000
NvRegTxRingPhysAddr = 0x100,
NvRegRxRingPhysAddr = 0x104,
NvRegRingSizes = 0x108,
#define NVREG_RINGSZ_TXSHIFT 0
#define NVREG_RINGSZ_RXSHIFT 16
NvRegUnkTransmitterReg = 0x10c,
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
#define NVREG_LINKSPEED_10MBPS 1000
#define NVREG_LINKSPEED_100MBPS 100
#define NVREG_LINKSPEED_1000MBPS 50
#define NVREG_LINKSPEED_MASK 0xFFF
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
NvRegUnknownSetupReg3 = 0x13C,
#define NVREG_UNKSETUP3_VAL1 0x200010
NvRegUnknownSetupReg7 = 0x140,
#define NVREG_UNKSETUP7_VAL1 0x300010
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
#define NVREG_TXRXCTL_BIT1 0x0002
#define NVREG_TXRXCTL_BIT2 0x0004
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
#define NVREG_TXRXCTL_DESC_1 0x0000
#define NVREG_TXRXCTL_DESC_2 0x2100
#define NVREG_TXRXCTL_DESC_3 0x2200
#define NVREG_TXRXCTL_VLANSTRIP 0x0040
#define NVREG_TXRXCTL_VLANINS 0x0080
NvRegTxRingPhysAddrHigh = 0x148,
NvRegRxRingPhysAddrHigh = 0x14C,
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
#define NVREG_MIISTAT_MASK 0x000F
#define NVREG_MIISTAT_MASK2 0x000F
NvRegUnknownSetupReg4 = 0x184,
#define NVREG_UNKSETUP4_VAL 8
NvRegAdapterControl = 0x188,
#define NVREG_ADAPTCTL_START 0x02
#define NVREG_ADAPTCTL_LINKUP 0x04
#define NVREG_ADAPTCTL_PHYVALID 0x40000
#define NVREG_ADAPTCTL_RUNNING 0x100000
#define NVREG_ADAPTCTL_PHYSHIFT 24
NvRegMIISpeed = 0x18c,
#define NVREG_MIISPEED_BIT8 (1<<8)
#define NVREG_MIIDELAY 5
NvRegMIIControl = 0x190,
#define NVREG_MIICTL_INUSE 0x08000
#define NVREG_MIICTL_WRITE 0x00400
#define NVREG_MIICTL_ADDRSHIFT 5
NvRegMIIData = 0x194,
NvRegWakeUpFlags = 0x200,
#define NVREG_WAKEUPFLAGS_VAL 0x7770
#define NVREG_WAKEUPFLAGS_BUSYSHIFT 24
#define NVREG_WAKEUPFLAGS_ENABLESHIFT 16
#define NVREG_WAKEUPFLAGS_D3SHIFT 12
#define NVREG_WAKEUPFLAGS_D2SHIFT 8
#define NVREG_WAKEUPFLAGS_D1SHIFT 4
#define NVREG_WAKEUPFLAGS_D0SHIFT 0
#define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01
#define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02
#define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04
#define NVREG_WAKEUPFLAGS_ENABLE 0x1111
NvRegPatternCRC = 0x204,
NvRegPatternMask = 0x208,
NvRegPowerCap = 0x268,
#define NVREG_POWERCAP_D3SUPP (1<<30)
#define NVREG_POWERCAP_D2SUPP (1<<26)
#define NVREG_POWERCAP_D1SUPP (1<<25)
NvRegPowerState = 0x26c,
#define NVREG_POWERSTATE_POWEREDUP 0x8000
#define NVREG_POWERSTATE_VALID 0x0100
#define NVREG_POWERSTATE_MASK 0x0003
#define NVREG_POWERSTATE_D0 0x0000
#define NVREG_POWERSTATE_D1 0x0001
#define NVREG_POWERSTATE_D2 0x0002
#define NVREG_POWERSTATE_D3 0x0003
NvRegVlanControl = 0x300,
#define NVREG_VLANCONTROL_ENABLE 0x2000
NvRegMSIXMap0 = 0x3E0,
NvRegMSIXMap1 = 0x3E4,
NvRegMSIXIrqStatus = 0x3F0,
NvRegPowerState2 = 0x600,
#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11
#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001
};
#define EEPROM_INDEX_MACADDR 0x101
#define FLAG_MASK_V1 0xffff0000
#define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1)
#define NV_TX_LASTPACKET (1<<16)
#define NV_TX_RETRYERROR (1<<19)
#define NV_TX_FORCED_INTERRUPT (1<<24)
#define NV_TX_DEFERRED (1<<26)
#define NV_TX_CARRIERLOST (1<<27)
#define NV_TX_LATECOLLISION (1<<28)
#define NV_TX_UNDERFLOW (1<<29)
#define NV_TX_ERROR (1<<30)
#define NV_TX_VALID (1<<31)
#define NV_RX_DESCRIPTORVALID (1<<16)
#define NV_RX_MISSEDFRAME (1<<17)
#define NV_RX_SUBSTRACT1 (1<<18)
#define NV_RX_ERROR1 (1<<23)
#define NV_RX_ERROR2 (1<<24)
#define NV_RX_ERROR3 (1<<25)
#define NV_RX_ERROR4 (1<<26)
#define NV_RX_CRCERR (1<<27)
#define NV_RX_OVERFLOW (1<<28)
#define NV_RX_FRAMINGERR (1<<29)
#define NV_RX_ERROR (1<<30)
#define NV_RX_AVAIL (1<<31)
//PhyGetLinkState
#define PHY_LINK_RUNNING 0x01
#define PHY_LINK_100MBPS 0x02
#define PHY_LINK_10MBPS 0x04
#define PHY_LINK_FULL_DUPLEX 0x08
#define PHY_LINK_HALF_DUPLEX 0x10
//Register access macros for XBOX
#define BASE 0xFEF00000
#define REG(x) (*((DWORD *)(BASE+(x))))
#define REGW(x) (*((WORD *)(BASE+(x))))
#define REGB(x) (*((BYTE *)(BASE+(x))))
typedef enum _MEMORY_CACHING_TYPE_ORIG {
MmFrameBufferCached = 2
} MEMORY_CACHING_TYPE_ORIG;
typedef enum _MEMORY_CACHING_TYPE {
MmNonCached = 0,
MmCached = 1,
MmWriteCombined = MmFrameBufferCached,
MmHardwareCoherentCached,
MmNonCachedUnordered, // IA64
MmUSWCCached,
MmMaximumCacheType
} MEMORY_CACHING_TYPE;
/*
MmNonCached : The requested memory should not be cached by the processor.
MmCached : The processor should cache the requested memory.
MmWriteCombined : The requested memory should not be cached by the processor,
but writes to the memory can be combined by the processor.
*/
//Checks for possible received packets
static int PktdrvRecvInterrupt(void)
{
ULONG p;
ULONG flag;
BOOLEAN fatal;
int handled;
int n=0;
//Look for next entry in Rx ring and read its flag
while(1)
{
p=g_s->RxBufferNext;
flag=*((ULONG *)(p+4));
if (flag & NV_RX_AVAIL) return n; //we received nothing!
if ((flag & NV_RX_DESCRIPTORVALID) == 0)
{
//Not a received packet
}
else
{
fatal=FALSE;
if (flag & NV_RX_ERROR)
{
if (flag & NV_RX_FRAMINGERR) { /* not fatal */ }
if (flag & NV_RX_OVERFLOW) { fatal=TRUE; }
if (flag & NV_RX_CRCERR) { fatal=TRUE; }
if (flag & NV_RX_ERROR4) { fatal=TRUE; }
if (flag & NV_RX_ERROR3) { fatal=TRUE; }
if (flag & NV_RX_ERROR2) { fatal=TRUE; }
if (flag & NV_RX_ERROR1) { fatal=TRUE; }
}
if (!fatal)
{
//Call user callback and warn that a packet has been received
//Phys Addr of packet is *p
//Length of packet is 1 up to 2046 bytes
//Length = ( (*((ULONG *)(p+4))) & 0x7FF ) + 1
handled=Pktdrv_Callback(
(unsigned char *)( (*((ULONG *)p))-g_s->PhysicalMinusVirtual),
(unsigned int)( ( (*((ULONG *)(p+4))) & 0x7FF ) + 1 ) );
if (!handled)
return n; //We probably lack space up there
else
n++;
}
}
//Empty the entry
*((ULONG *)(p+4))=NV_RX_AVAIL | 2045;
//Have RxBufferNext Point to next entry in ring
if (g_s->RxBufferNext==g_s->RxBufferTail) //return to start of ring?
g_s->RxBufferNext=g_s->RxBufferDesc;
else
g_s->RxBufferNext+=8;
};
return n;
}
//Detects if Tx ring is full or not
static BOOLEAN PktdrvSendReady(void)
{
return (g_s->QueuedTxPkts!=g_s->NbrTxBuffers);
}
//Checks for a patcket to send
static void PktdrvSendInterrupt(void)
{
ULONG p,flag;
//Before we send any packet, let's check if last packets have been sent
while (g_s->TxBufferLast!=g_s->TxBufferNext)
{
p=g_s->TxBufferLast;
flag=*((ULONG *)(p+4));
if ((flag & NV_TX_VALID) == 0)
{
//Packet is gone, reduce counter and check next one.
//Note that errors and actual number of bytes sent
//can be read from flag right now and right here!
//Actual number is higher because of padding...
g_s->QueuedTxPkts--;
//Let's cleanup
*((ULONG *)p)=0;
*((ULONG *)(p+4))=0;
//Have TxBufferLast point to next entry
if (g_s->TxBufferLast==g_s->TxBufferTail)
g_s->TxBufferLast=g_s->TxBufferDesc;
else
g_s->TxBufferLast+=8;
}
else
break; //packet not sent already, we will check later
}
}
static void PktdrvSendPacket(unsigned char *buffer, int length)
{
ULONG p;
if (PktdrvSendReady()) //Do we have room in the Tx ring?
{
//p points to next free entry of Tx ring descriptor
p=g_s->TxBufferNext;
MmLockUnlockBufferPages(
(ULONG)buffer,
length,
0);
*((ULONG *)p) = MmGetPhysicalAddress(buffer);
*((ULONG *)(p+4)) = (length-1) |
NV_TX_VALID |
NV_TX_LASTPACKET;
g_s->QueuedTxPkts++;
//Have TxBufferNext point to next entry
if (g_s->TxBufferNext==g_s->TxBufferTail) //return to start of ring?
g_s->TxBufferNext=g_s->TxBufferDesc;
else
g_s->TxBufferNext+=8;
REG(NvRegTxRxControl)=NVREG_TXRXCTL_KICK;
}
else
{
//Tx ring is full
//User should do : while(Xnet_GetQueuedPkts()>=n) { /*wait*/ }; then send pkt
//That will prevent the loss of sent packet right here
//Where n is the number of buffers (ring) where pending outcoming packets are
//stored. In most case n=1 (just one buffer is used to send 1 packet at a time)
}
}
//Starts Pktdrv
static void PktdrvStartSendRecv(void)
{
REG(NvRegLinkSpeed) = NVREG_LINKSPEED_FORCE | g_s->Speed;
REG(NvRegTransmitterControl) = NVREG_SendCTL_START;
REG(NvRegReceiverControl) = NVREG_RCVCTL_START;
REG(NvRegTxRxControl)= NVREG_TXRXCTL_KICK | NVREG_TXRXCTL_BIT1;
}
//Stops Pktdrv
static void PktdrvStopSendRecv(void)
{
int i;
REG(NvRegLinkSpeed)=0;
REG(NvRegReceiverControl)=0;
REG(NvRegTransmitterControl)=0;
for(i=0;i<500;i++)
{
if ( ((REGB(NvRegReceiverStatus) & NVREG_RCVSTAT_BUSY)==0)
&&
((REGB(NvRegTransmitterStatus) & NVREG_SendSTAT_BUSY)==0) )
break;
KeStallExecutionProcessor(10); //Wait 10 microseconds
}
REG(NvRegTxRxControl)=NVREG_TXRXCTL_BIT2;
for(i=0;i<100000;i++)
{
if (REGB(NvRegTxRxControl) & NVREG_TXRXCTL_IDLE) break;
KeStallExecutionProcessor(10);
}
REG(NvRegTxRxControl)=0;
}
//Resets Pktdrv
static void PktdrvReset(void)
{
PktdrvStopSendRecv();
REG(NvRegTxRxControl)=NVREG_TXRXCTL_RESET;
KeStallExecutionProcessor(10); //10 microseconds of busy-wait
REG(NvRegTxRxControl)=0;
KeStallExecutionProcessor(10);
REG(NvRegUnknownSetupReg4)=0;
REG(NvRegIrqMask)=0;
REG(NvRegWakeUpFlags)=0;
REG(NvRegUnknownSetupReg6)=0;
REG(NvRegTxRingPhysAddr)=0;
REG(NvRegRxRingPhysAddr)=0;
REG(NvRegUnkTransmitterReg)=0;
REG(NvRegLinkSpeed)=0;
REG(NvRegTransmitterStatus)=REG(NvRegTransmitterStatus);
REG(NvRegReceiverStatus)=REG(NvRegReceiverStatus);
REG(NvRegMIIStatus)=REG(NvRegMIIStatus);
REG(NvRegIrqStatus)=REG(NvRegIrqStatus);
}
//Checks possible speed or duplex mode change
static void PktdrvMiiInterrupt(int mode)
{
//Verifies if speed or duplex mode changed
//mode=1 -> startup mode (calls PhyGetLinkState(0))
//(used at startup, before Pktdrv driver is started)
//mode=0 -> running mode (calls PhyGetLinkState(1))
//(used in interrupt, while Pktdrv driver is running)
ULONG state,dummy;
mode&=1; //only 0 or 1 is accepted
dummy=REG(NvRegAdapterControl); //just read it
state=PhyGetLinkState(1-mode);
if ((mode==0)&&(state==g_s->OldPhyState)) return; //All is ok, remain silent
//We want details (startup) or state changed (both modes)
#ifdef DISPLAYMSG
debugPrint("Transceiver link state :\n");
if (state & PHY_LINK_RUNNING)
debugPrint(" Running at ");
else
debugPrint(" NOT running at ");
if (state & PHY_LINK_100MBPS)
debugPrint("100 Mbps ");
else
if (state & PHY_LINK_10MBPS)
debugPrint("10 Mbps ");
else
debugPrint("unknown speed ");
if (state & PHY_LINK_FULL_DUPLEX)
debugPrint("in full duplex mode\n");
else
if (state & PHY_LINK_HALF_DUPLEX)
debugPrint("in half duplex mode\n");
else
debugPrint("in unknown duplex mode\n");
#endif
if (mode==0) PktdrvStopSendRecv(); //Pktdrv is running. Stop it.
if (state & PHY_LINK_10MBPS) //update Speed member in structure
g_s->Speed=NVREG_LINKSPEED_10MBPS; //decimal value 1000!!!
else
g_s->Speed=NVREG_LINKSPEED_100MBPS; //decimal value 100
if (state & PHY_LINK_FULL_DUPLEX) //update mode in Pktdrv register
REG(NvRegDuplexMode) &= NVREG_DUPLEX_MODE_FDMASK;
else
REG(NvRegDuplexMode) |= NVREG_DUPLEX_MODE_HDFLAG;
if (mode==0) PktdrvStartSendRecv(); //Mode changed. Restart Pktdrv.
//This function will read g_s->Speed and program speed link register.
g_s->OldPhyState=state;
}
static BOOLEAN __stdcall MyPktdrvIsr(PKINTERRUPT Interrupt, PVOID ServiceContext)
{
REG(NvRegIrqMask)=0;
if (g_running)
{
KeInsertQueueDpc(&g_s->MyPktdrvDpcObject,NULL,NULL);
g_s->PktdrvIsrCounter++;
}
return TRUE;
}
static void __stdcall MyPktdrvDpc( PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2 )
{
//DPCs allow to use non reentrant procedures (called sequentially, FOR SURE).
//CAUTION : if you use fpu in DPC you have to save & restore yourself fpu state!!!
//(fpu=floating point unit, i.e the coprocessor executing floating point opcodes)
ULONG irq_status;
ULONG mii_status;
if (g_running==0) return;
mii_status=0;
irq_status= NVREG_IRQSTAT_BIT0EVENT |
NVREG_IRQSTAT_BIT1EVENT |
NVREG_IRQSTAT_BIT2EVENT |
NVREG_IRQSTAT_UNKEVENT;
while (irq_status)
{
if (irq_status & NVREG_IRQSTAT_MIIEVENT) PktdrvMiiInterrupt(0);
REG(NvRegMIIStatus)=mii_status;
REG(NvRegIrqStatus)=irq_status;
//uncomment this line if you want your callback to be called as soon as packet arrived
// PktdrvRecvInterrupt(); //Check if we received packets // (let them stock up)
PktdrvSendInterrupt(); //Check if we have a packet to send
if (irq_status & NVREG_IRQSTAT_BIT1EVENT)
REG(NvRegTxRxControl)=NVREG_TXRXCTL_BIT1;
mii_status=REG(NvRegMIIStatus);
irq_status=REG(NvRegIrqStatus);
};
REG(NvRegIrqMask)= NVREG_IRQ_LINK |
NVREG_IRQ_TX_OK |
NVREG_IRQ_TX_ERROR |
NVREG_IRQ_RX_NOBUF |
NVREG_IRQ_RX |
NVREG_IRQ_RX_ERROR;
return;
}
void Pktdrv_Quit(void)
{
if (g_running==0) return;
g_running=0;
PktdrvStopSendRecv();
PktdrvReset();
KeDisconnectInterrupt(&s_MyInterruptObject);
MmFreeContiguousMemory((void *)g_s->TxBufferDesc);
free(g_s);
}
//Returns 1 if everything is ok
int Pktdrv_Init(void)
{
int n,len,type;
ULONG buffers_addr;
ULONG buffers_physaddr;
ULONG status;
ULONG buffers_total_size;
ULONG p,p2;
ULONG RandomValue;
if (g_running==1) return 1;
g_s=(struct s_MyStructures *)malloc(sizeof(struct s_MyStructures));
//g_s holds the various needed structures
if (!g_s)
{
debugPrint("Can't allocate global structure.\n");
return 0;
}
g_s->Vector=HalGetInterruptVector(4,&g_s->IrqLevel);
KeInitializeDpc(&g_s->MyPktdrvDpcObject,&MyPktdrvDpc,&g_s->MyContext);
KeInitializeInterrupt( &s_MyInterruptObject,
&MyPktdrvIsr,
&g_s->MyContext,
g_s->Vector,
g_s->IrqLevel,
LevelSensitive,
TRUE );
PktdrvReset();
g_s->NbrRxBuffersWithoutCheck=NBBUFF; //Total buffers = NBBUFF+2 (Tx&Rx Descriptors)
n = g_s->NbrRxBuffersWithoutCheck;
g_s->NbrRxBuffers = MIN(n,256);
g_s->NbrTxBuffers = MIN(n,256);
//Rx ring will point to the pool of n allocated buffers
//Tx ring is empty at startup may point to any contiguous buffer physical address
buffers_total_size = ((n+1+1)<<11);
//allocates n+1+1 DMA buffers 2048 bytes each
buffers_addr=(ULONG)MmAllocateContiguousMemoryEx(
buffers_total_size,
0, //lowest acceptable
0x10000, //highest acceptable
0, //no need to align to specific boundaries multiple
MmNonCachedUnordered); //4
if (!buffers_addr)
buffers_addr=(ULONG)MmAllocateContiguousMemoryEx(
buffers_total_size,
0, //lowest acceptable
0xFFFFFFFF, //highest acceptable
0, //no need to align to specific boundaries multiple
MmNonCachedUnordered); //4
if (!buffers_addr)
{
debugPrint("Can't allocate DMA reception buffers\n");
free(g_s);
return 0;
}
//Write zeroes in first buffer and second buffer (descriptors)
memset((void *)buffers_addr, 0, 4096);
buffers_physaddr=MmGetPhysicalAddress((void *)buffers_addr);
g_s->PhysicalMinusVirtual = buffers_physaddr - buffers_addr;
g_s->RxBufferDesc = buffers_addr + 2048;
g_s->RxBufferNext = buffers_addr + 2048;
g_s->RxBufferTail = buffers_addr + 2048 + g_s->NbrRxBuffers * 8 - 8;
g_s->TxBufferDesc = buffers_addr;
g_s->TxBufferLast = buffers_addr;
g_s->TxBufferNext = buffers_addr;
g_s->TxBufferTail = buffers_addr + 8 * g_s->NbrTxBuffers - 8;
p=buffers_addr + 4096 + 2 + g_s->PhysicalMinusVirtual; //Points 1st buffer at offset 2
p2=buffers_addr + 2048;
while(p2 <= g_s->RxBufferTail)
{
*((DWORD *)p2)=p; //Physical address of offset 2 of buffer
*((DWORD *)(p2+4))=NV_RX_AVAIL | 2045; //Makes all Rx buffers available
//2046 bytes available for incoming packet at offset 2
p2+=8;
p+=2048;
};
//Buffers description :
//1st buffer is a list of n pointers+flags (every 8 bytes) and is Tx ring descriptor
//2nd buffer is a list of n pointers+flags (every 8 bytes) and is Rx ring descriptor
//3rd buffer and following ones are pointed by the Rx ring pointers (at offset 2)
//(n buffers used for packet receiving at startup while Tx ring is all zeroed)
//Total : 1+1+n buffers
//Descriptor is a list of 8 bytes values (a 32 bits physical address + a 32 bits flag)
//The flag has the length (minus one) of available room/received packet/to send packet
//in the lower 11 bits of the 32 bits flag
len=0;
ExQueryNonVolatileSetting(EEPROM_INDEX_MACADDR,&type,g_s->Ethaddr,6,&len);
if (len!=6)
debugPrint("Can't read ethernet address from EEPROM\n");
#ifdef DISPLAYMSG
else
debugPrint("EEPROM MacAddress = %02x %02x %02x %02x %02x %02x\n",
g_s->Ethaddr[0],
g_s->Ethaddr[1],
g_s->Ethaddr[2],
g_s->Ethaddr[3],
g_s->Ethaddr[4],
g_s->Ethaddr[5]);
#endif
g_s->Speed=NVREG_LINKSPEED_100MBPS;
g_s->Ethaddr_reversed[0]=g_s->Ethaddr[5];
g_s->Ethaddr_reversed[1]=g_s->Ethaddr[4];
g_s->Ethaddr_reversed[2]=g_s->Ethaddr[3];
g_s->Ethaddr_reversed[3]=g_s->Ethaddr[2];
g_s->Ethaddr_reversed[4]=g_s->Ethaddr[1];
g_s->Ethaddr_reversed[5]=g_s->Ethaddr[0];
//Writing the MAC address (6 bytes ethernet address)
REG(NvRegMacAddrA)=*((DWORD *)&g_s->Ethaddr_reversed[0]);
REG(NvRegMacAddrB)=(ULONG)(*((WORD *)&g_s->Ethaddr_reversed[4]));
REG(NvRegMulticastMaskA)=0xFFFFFFFF;
REG(NvRegMulticastMaskB)=0x0000FFFF;
REG(NvRegMulticastAddrA)=*((DWORD *)&g_s->Ethaddr[0]); //Yes, not reversed!
REG(NvRegMulticastAddrB)=(ULONG)(*((WORD *)&g_s->Ethaddr[4]));
RandomValue=0x1234+*((DWORD *)g_s->Ethaddr)+*((WORD *)&g_s->Ethaddr[4]);
//In case of ethernet colision, random duration pauses are used before retry
REG(NvRegRandomSeed) = (RandomValue & NVREG_RNDSEED_MASK) | NVREG_RNDSEED_FORCE;
REG(NvRegOffloadConfig)=NVREG_OFFLOAD_NORMAL; //1518 bytes
REG(NvRegPacketFilterFlags)=NVREG_PFF_ALWAYS_MYADDR;
REG(NvRegDuplexMode)=NVREG_DUPLEX_MODE_FORCEH;
REG(NvRegUnknownSetupReg1)=NVREG_UNKSETUP1_VAL;
REG(NvRegUnknownSetupReg2)=NVREG_UNKSETUP2_VAL;
//Writing the DMA buffers addresses and sizes
REG(NvRegTxRingPhysAddr)= g_s->TxBufferDesc + g_s->PhysicalMinusVirtual; //1st buf phys
REG(NvRegRxRingPhysAddr)= g_s->RxBufferDesc + g_s->PhysicalMinusVirtual; //2nd buf phys
REG(NvRegRingSizes)= ((g_s->NbrRxBuffers-1)<<16) | (g_s->NbrTxBuffers-1);
REG(NvRegUnknownSetupReg7)=NVREG_UNKSETUP7_VAL1;
REG(NvRegUnknownSetupReg3)=NVREG_UNKSETUP7_VAL1; //Yes, Val7 into Reg3!
REG(NvRegAdapterControl) = (1 << NVREG_ADAPTCTL_PHYSHIFT) | NVREG_ADAPTCTL_PHYVALID;
REG(NvRegMIISpeed)= NVREG_MIISPEED_BIT8 | NVREG_MIIDELAY;
KeStallExecutionProcessor(50); //50 micro seconds of busy-wait
g_running=1;
//XBOX specific (nForce specific)
if (PhyInitialize(0,0)<0) //Initialize transceiver
{
debugPrint("PhyInitialize error\n");
Pktdrv_Quit();
return 0;
}
REG(NvRegAdapterControl)=NVREG_ADAPTCTL_RUNNING;
KeStallExecutionProcessor(50);
PktdrvMiiInterrupt(1); //force display/update of current speed and duplex mode
PktdrvStartSendRecv();
REG(NvRegMIIStatus)=REG(NvRegMIIStatus);
REG(NvRegIrqStatus)=REG(NvRegIrqStatus);
REG(NvRegUnknownSetupReg4)=NVREG_UNKSETUP4_VAL;
REG(NvRegIrqMask)= NVREG_IRQ_LINK |
NVREG_IRQ_TX_OK |
NVREG_IRQ_TX_ERROR |
NVREG_IRQ_RX_NOBUF |
NVREG_IRQ_RX |
NVREG_IRQ_RX_ERROR;
status=KeConnectInterrupt(&s_MyInterruptObject);
status = 1; // KeConnectInterrupt is returning 0... but it seems to work
if (status==0)
{
debugPrint("KeConnectInterrupt error\n");
Pktdrv_Quit();
return 0;
}
#ifdef DISPLAYMSG
else
debugPrint("Network interruption initialized successfully\n");
#endif
return 1;
}
int Pktdrv_ReceivePackets(void)
{
if (g_running) return PktdrvRecvInterrupt(); //returns nbr of packets accepted by callback
return 0;
}
void Pktdrv_SendPacket(unsigned char *buffer,int length)
{
if (g_running)
{
PktdrvSendInterrupt();
//if QueuedTxPkts>=n (n=number of outgoing buffers -ring- in calling app)
//then packet will not be sent (app has to wait until QueuedTxPkts<n)
PktdrvSendPacket(buffer,length);
}
}
void Pktdrv_GetEthernetAddr(unsigned char *address)
{
if ((address)&&(g_running))
memcpy(address,g_s->Ethaddr,6);
}
int Pktdrv_GetQueuedTxPkts(void)
{
if (g_running)
{
PktdrvSendInterrupt(); //detects any sent packet and updates QueuedTxPkts
return g_s->QueuedTxPkts;
}
else
return 0;
}

11
lib/net/pktdrv/pktdrv.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef _Pktdrv_
#define _Pktdrv_
int Pktdrv_Init(void);
void Pktdrv_Quit(void);
int Pktdrv_ReceivePackets(void);
void Pktdrv_SendPacket(unsigned char *buffer,int length);
void Pktdrv_GetEthernetAddr(unsigned char *address);
int Pktdrv_GetQueuedTxPkts(void);
#endif