2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
10 # $Id: ps2ip.c 577 2004-09-14 14:41:46Z pixel $
11 # PS2 TCP/IP STACK FOR IOP
29 #include <lwip/memp.h>
31 #include <lwip/tcpip.h>
32 #include <lwip/netif.h>
33 #include <lwip/dhcp.h>
34 #include <netif/loopif.h>
35 #include <netif/etharp.h>
37 #include "ps2ip_internal.h"
38 #include "arch/sys_arch.h"
40 #define SYS_MBOX_SIZE 64
43 struct sys_mbox_msg
* pNext
;
50 void* apvMSG
[ SYS_MBOX_SIZE
];
57 typedef struct ip_addr IPAddr
;
59 #define MODNAME "TCP/IP Stack"
60 IRX_ID( MODNAME
, 1, 3 );
62 extern struct irx_export_table _exp_ps2ip
;
65 static int iTimerDHCP
= 0;
66 #endif /* PS2IP_DHCP */
70 #endif /* LWIP_HAVE_LOOPIF */
72 static u16_t
inline GenNextMBoxIndex ( u16_t u16Index
) {
73 return ( u16Index
+ 1 ) % SYS_MBOX_SIZE
;
74 } /* end GenNextMBoxIndex */
76 static int inline IsMessageBoxFull ( sys_mbox_t apMBox
) {
77 return GenNextMBoxIndex ( apMBox
-> u16Last
) == apMBox
-> u16First
;
78 } /* end IsMessageBoxFull */
80 static int inline IsMessageBoxEmpty ( sys_mbox_t apMBox
) {
81 return apMBox
-> u16Last
== apMBox
-> u16First
;
82 } /* end IsMessageBoxEmpty */
84 void PostInputMSG ( sys_mbox_t pMBox
, void* pvMSG
) {
86 pMBox
-> apvMSG
[ pMBox
-> u16Last
] = pvMSG
;
87 pMBox
-> u16Last
= GenNextMBoxIndex ( pMBox
-> u16Last
);
89 if ( pMBox
-> iWaitFetch
> 0 ) iSignalSema ( pMBox
-> Mail
);
91 } /* end PostInputMSG */
93 int ps2ip_getconfig ( char* pszName
, t_ip_info
* pInfo
) {
95 struct netif
* pNetIF
= netif_find ( pszName
);
97 if ( pNetIF
== NULL
) {
98 mips_memset ( pInfo
, 0, sizeof ( *pInfo
) );
102 strcpy ( pInfo
-> netif_name
, pszName
);
104 pInfo
-> ipaddr
.s_addr
= pNetIF
-> ip_addr
.addr
;
105 pInfo
-> netmask
.s_addr
= pNetIF
-> netmask
.addr
;
106 pInfo
-> gw
.s_addr
= pNetIF
-> gw
.addr
;
107 mips_memcpy( pInfo
-> hw_addr
,pNetIF
-> hwaddr
, sizeof ( pInfo
-> hw_addr
) );
109 if ( pNetIF
-> dhcp
) {
110 pInfo
-> dhcp_enabled
= 1;
111 pInfo
-> dhcp_status
= pNetIF
-> dhcp
->state
;
113 pInfo
-> dhcp_enabled
= 0;
114 pInfo
-> dhcp_status
= 0;
117 pInfo
-> dhcp_enabled
= 0;
118 #endif /* LWIP_DHCP */
121 } /* end ps2ip_getconfig */
123 int ps2ip_setconfig ( t_ip_info
* pInfo
) {
125 struct netif
* pNetIF
= netif_find ( pInfo
-> netif_name
);
127 if ( !pNetIF
) return 0;
129 netif_set_ipaddr ( pNetIF
, ( IPAddr
* )&pInfo
-> ipaddr
);
130 netif_set_netmask ( pNetIF
, ( IPAddr
* )&pInfo
-> netmask
);
131 netif_set_gw ( pNetIF
, ( IPAddr
* )&pInfo
-> gw
);
133 if ( pInfo
-> dhcp_enabled
) {
134 if ( !pNetIF
-> dhcp
) dhcp_start ( pNetIF
);
136 if ( pNetIF
-> dhcp
) dhcp_stop ( pNetIF
);
138 #endif /* LWIP_DHCP */
141 } /* end ps2ip_setconfig */
143 #define ALARM_TCP 0x00000001
144 #define ALARM_ARP 0x00000002
145 #define ALARM_MSK ( ALARM_TCP | ALARM_ARP )
147 typedef struct AlarmData
{
150 unsigned long m_EventMask
;
151 iop_sys_clock_t m_Clock
;
155 unsigned int _alarm ( void* apArg
) {
157 AlarmData
* lpData
= ( AlarmData
* )apArg
;
159 iSetEventFlag ( lpData
-> m_EventFlag
, lpData
-> m_EventMask
);
161 return lpData
-> m_Clock
.lo
;
165 static void TimerThread ( void* apArg
) {
173 lTCPData
.m_EventFlag
=
174 lARPData
.m_EventFlag
= CreateEventFlag ( &lEvent
);
175 lTCPData
.m_EventMask
= ALARM_TCP
;
176 lARPData
.m_EventMask
= ALARM_ARP
;
177 USec2SysClock ( TCP_TMR_INTERVAL
* 1024, &lTCPData
.m_Clock
);
178 USec2SysClock ( ARP_TMR_INTERVAL
* 1024, &lARPData
.m_Clock
);
180 SetAlarm ( &lTCPData
.m_Clock
, _alarm
, &lTCPData
);
181 SetAlarm ( &lARPData
.m_Clock
, _alarm
, &lARPData
);
187 WaitEventFlag ( lTCPData
.m_EventFlag
, ALARM_MSK
, WEF_CLEAR
| WEF_OR
, &lRes
);
190 if ( lRes
& ALARM_TCP
) tcp_tmr ();
192 if ( lRes
& ALARM_ARP
) etharp_tmr ();
196 } /* end TimerThread */
198 static void InitTimer ( void ) {
200 iop_thread_t lThread
= { TH_C
, 0, TimerThread
, 0x800, 0x22 };
201 int lTID
= CreateThread ( &lThread
);
203 if ( lTID
< 0 ) ExitDeleteThread ();
205 StartThread ( lTID
, NULL
);
207 } /* end InitTimer */
209 typedef struct InputMSG
{
211 struct netif
* pNetIF
;
214 #define MSG_QUEUE_SIZE 16
216 static InputMSG aMSGs
[ MSG_QUEUE_SIZE
];
217 static u8_t u8FirstMSG
= 0;
218 static u8_t u8LastMSG
= 0;
220 static u8_t
inline GetNextMSGQueueIndex ( u8_t u8Index
) {
221 return ( u8Index
+ 1 ) % MSG_QUEUE_SIZE
;
222 } /* end GetNextMSGQueueIndex */
224 static int inline IsMSGQueueFull ( void ) {
225 return GetNextMSGQueueIndex ( u8LastMSG
) == u8FirstMSG
;
226 } /* end IsMSGQueueFull */
228 static void InputCB ( void* pvArg
) {
230 InputMSG
* pMSG
= ( InputMSG
* )pvArg
;
231 struct pbuf
* pInput
= pMSG
-> pInput
;
232 struct netif
* pNetIF
= pMSG
-> pNetIF
;
235 CpuSuspendIntr ( &iFlags
);
236 u8FirstMSG
= GetNextMSGQueueIndex ( u8FirstMSG
);
237 CpuResumeIntr ( iFlags
);
239 switch ( ( ( struct eth_hdr
* )( pInput
-> payload
) ) -> type
) {
242 etharp_ip_input ( pNetIF
, pInput
);
243 pbuf_header ( pInput
, -14 );
244 ip_input ( pInput
, pNetIF
);
249 pNetIF
, ( struct eth_addr
* )&pNetIF
-> hwaddr
, pInput
251 default: pbuf_free ( pInput
);
257 extern sys_mbox_t g_TCPIPMBox
;
259 err_t
ps2ip_input ( struct pbuf
* pInput
, struct netif
* pNetIF
) {
260 //When ps2smap receive data, it invokes this function. It'll be called directly by the interrupthandler, which means we are
261 //running in an interrupt-context. We'll pass on the data to the tcpip message-thread by adding a callback message. If the
262 //messagebox is full, we can't wait for the tcpip-thread to process a message to make room for our message, since we're
263 //in interrupt-context. If the messagebox or messagequeue is full, drop the packet.
265 struct tcpip_msg
* pMSG
;
267 if ( IsMessageBoxFull ( g_TCPIPMBox
) || IsMSGQueueFull () ) {
268 pbuf_free ( pInput
);
271 //Allocate messagequeue entry.
272 pIMSG
= &aMSGs
[ u8LastMSG
];
273 u8LastMSG
= GetNextMSGQueueIndex ( u8LastMSG
);
274 //Initialize the InputMSG.
275 pIMSG
-> pInput
= pInput
;
276 pIMSG
-> pNetIF
= pNetIF
;
277 pMSG
= ( struct tcpip_msg
* )memp_malloc ( MEMP_TCPIP_MSG
);
280 pbuf_free ( pInput
);
284 pMSG
-> type
= TCPIP_MSG_CALLBACK
;
285 pMSG
-> msg
.cb
.f
= InputCB
;
286 pMSG
-> msg
.cb
.ctx
= pIMSG
;
287 PostInputMSG ( g_TCPIPMBox
, pMSG
);
291 } /* end ps2ip_input */
293 void ps2ip_Stub ( void ) {
295 } /* end ps2ip_Stub */
297 int ps2ip_ShutDown ( void ) {
301 } /* end ps2ip_ShutDown */
303 static void AddLoopIF ( void ) {
309 IP4_ADDR( &IP
, 127, 0, 0, 1 );
310 IP4_ADDR( &NM
, 255, 0, 0, 0 );
311 IP4_ADDR( &GW
, 127, 0, 0, 1 );
313 netif_add ( &LoopIF
, &IP
, &NM
, &GW
, NULL
, loopif_init
, tcpip_input
);
315 } /* end AddLoopIF */
316 #endif /* LWIP_HAVE_LOOPIF */
317 int _start ( int argc
,char** argv
) {
321 RegisterLibraryEntries ( &_exp_ps2ip
);
328 lSema
= sys_sem_new ( 0 );
329 tcpip_init ( ( void ( * )( void* ) )SignalSema
, ( void* )lSema
);
331 sys_sem_free ( lSema
);
334 #endif /* LWIP_HAVE_LOOPIF */
337 return MODULE_RESIDENT_END
;
341 #define SYS_THREAD_PRIO_BASE 0x22
343 sys_thread_t
sys_thread_new (
344 void ( *pFunction
)( void* ),void* pvArg
,int iPrio
347 iop_thread_t Info
= {
348 TH_C
, 0, pFunction
, 0x900, iPrio
+ SYS_THREAD_PRIO_BASE
352 iThreadID
= CreateThread ( &Info
);
354 if ( iThreadID
< 0 ) return -1;
356 StartThread ( iThreadID
, pvArg
);
360 } /* end sys_thread_new */
362 sys_mbox_t
sys_mbox_new ( void ) {
366 pMBox
= ( sys_mbox_t
)AllocSysMemory ( 0, sizeof ( struct sys_mbox
), 0 );
368 if ( !pMBox
) return NULL
;
370 pMBox
-> u16First
= pMBox
-> u16Last
= 0;
371 pMBox
-> Mail
= sys_sem_new ( 0 );
372 pMBox
-> Mutex
= sys_sem_new ( 1 );
373 pMBox
-> iWaitPost
= pMBox
-> iWaitFetch
= 0;
377 } /* end sys_mbox_new */
379 void sys_mbox_free ( sys_mbox_t pMBox
) {
381 if ( !pMBox
) return;
383 WaitSema ( pMBox
-> Mutex
);
385 sys_sem_free ( pMBox
-> Mail
);
386 sys_sem_free ( pMBox
-> Mutex
);
388 FreeSysMemory ( pMBox
);
390 } /* end sys_mbox_free */
392 void sys_mbox_post ( sys_mbox_t pMBox
, void* pvMSG
) {
396 if ( !pMBox
) return;
398 CpuSuspendIntr ( &Flags
);
400 while ( IsMessageBoxFull ( pMBox
) ) {
402 ++pMBox
-> iWaitPost
;
404 CpuResumeIntr ( Flags
);
405 WaitSema ( pMBox
-> Mail
);
406 CpuSuspendIntr ( &Flags
);
408 --pMBox
-> iWaitPost
;
412 pMBox
-> apvMSG
[ pMBox
-> u16Last
] = pvMSG
;
413 pMBox
-> u16Last
= GenNextMBoxIndex ( pMBox
-> u16Last
);
415 if ( pMBox
-> iWaitFetch
> 0 ) SignalSema ( pMBox
-> Mail
);
417 CpuResumeIntr ( Flags
);
419 } /* end sys_mbox_post */
421 u32_t
sys_arch_mbox_fetch ( sys_mbox_t pMBox
, void** ppvMSG
, u32_t u32Timeout
) {
426 CpuSuspendIntr ( &Flags
);
428 while ( IsMessageBoxEmpty ( pMBox
) ) {
432 ++pMBox
-> iWaitFetch
;
434 CpuResumeIntr ( Flags
);
435 u32WaitTime
= sys_arch_sem_wait ( pMBox
-> Mail
, u32Timeout
);
436 CpuSuspendIntr ( &Flags
);
438 --pMBox
-> iWaitFetch
;
440 if ( u32WaitTime
== SYS_ARCH_TIMEOUT
) {
441 u32Time
= u32WaitTime
;
445 u32Time
+= u32WaitTime
;
446 u32Timeout
-= u32WaitTime
;
450 *ppvMSG
= pMBox
-> apvMSG
[ pMBox
-> u16First
];
451 pMBox
-> u16First
= GenNextMBoxIndex ( pMBox
-> u16First
);
453 if ( pMBox
-> iWaitPost
> 0 ) SignalSema ( pMBox
-> Mail
);
455 CpuResumeIntr ( Flags
);
459 } /* end sys_arch_mbox_fetch */
461 sys_sem_t
sys_sem_new ( u8_t aCount
) {
463 iop_sema_t lSema
= { 1, 1, aCount
,1 };
466 retVal
= CreateSema ( &lSema
);
468 if ( retVal
<= 0 ) retVal
= SYS_SEM_NULL
;
472 } /* end sys_sem_new */
474 u32_t
sys_arch_sem_wait ( sys_sem_t aSema
, u32_t aTimeout
) {
477 return WaitSema ( aSema
);
480 iop_sys_clock_t lTimeout
;
481 int lTID
= GetThreadId ();
483 USec2SysClock ( aTimeout
* 1024, &lTimeout
);
484 SetAlarm ( &lTimeout
, ( unsigned ( * ) ( void* ) )iReleaseWaitThread
, ( void* )lTID
);
486 if ( !WaitSema ( aSema
) ) {
487 CancelAlarm ( ( unsigned ( * ) ( void* ) )iReleaseWaitThread
, ( void* )lTID
);
489 } else aTimeout
= SYS_ARCH_TIMEOUT
;
495 } /* end sys_arch_sem_wait */
497 void sys_sem_free ( sys_sem_t aSema
) {
499 if ( aSema
!= SYS_SEM_NULL
) DeleteSema ( aSema
);
501 } /* end sys_sem_free */