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:
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||
|
||||
4
Makefile
4
Makefile
@ -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
18
lib/net/Makefile
Normal 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
1
lib/net/lwip
Submodule
Submodule lib/net/lwip added at b9d0d80946
102
lib/net/nforceif/include/arch/cc.h
Normal file
102
lib/net/nforceif/include/arch/cc.h
Normal 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 */
|
||||
65
lib/net/nforceif/include/arch/sys_arch.h
Normal file
65
lib/net/nforceif/include/arch/sys_arch.h
Normal 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 */
|
||||
|
||||
443
lib/net/nforceif/include/lwipopts.h
Normal file
443
lib/net/nforceif/include/lwipopts.h
Normal 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 */
|
||||
370
lib/net/nforceif/src/driver.c
Normal file
370
lib/net/nforceif/src/driver.c
Normal 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;
|
||||
}
|
||||
431
lib/net/nforceif/src/sys_arch.c
Normal file
431
lib/net/nforceif/src/sys_arch.c
Normal 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
166
lib/net/pktdrv/license.txt
Normal 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
965
lib/net/pktdrv/pktdrv.c
Normal 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
11
lib/net/pktdrv/pktdrv.h
Normal 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
|
||||
Reference in New Issue
Block a user