fix for corrupted graphics when manipulating config files
[open-ps2-loader.git] / modules / network / SMSTCPIP / ps2ip.c
blob50af47a47564863bf498e8a44461ad05b5954ef1
1 /*
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
14 #include <types.h>
15 #include <stdio.h>
16 #include <intrman.h>
17 #include <loadcore.h>
18 #include <thbase.h>
19 #include <vblank.h>
20 #include <modload.h>
21 #include <sysclib.h>
22 #include <thevent.h>
23 #include <thsemap.h>
24 #include <libsd.h>
25 #include <sysmem.h>
27 #include "smsutils.h"
29 #include <lwip/memp.h>
30 #include <lwip/sys.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
42 struct sys_mbox_msg {
43 struct sys_mbox_msg* pNext;
44 void* pvMSG;
47 struct sys_mbox {
48 u16_t u16First;
49 u16_t u16Last;
50 void* apvMSG[ SYS_MBOX_SIZE ];
51 sys_sem_t Mail;
52 sys_sem_t Mutex;
53 int iWaitPost;
54 int iWaitFetch;
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;
64 #ifdef PS2IP_DHCP
65 static int iTimerDHCP = 0;
66 #endif /* PS2IP_DHCP */
68 #if LWIP_HAVE_LOOPIF
69 static NetIF LoopIF;
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 ) );
99 return 0;
100 } /* end if */
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 ) );
108 #if LWIP_DHCP
109 if ( pNetIF -> dhcp ) {
110 pInfo -> dhcp_enabled = 1;
111 pInfo -> dhcp_status = pNetIF -> dhcp->state;
112 } else {
113 pInfo -> dhcp_enabled = 0;
114 pInfo -> dhcp_status = 0;
115 } /* end else */
116 #else
117 pInfo -> dhcp_enabled = 0;
118 #endif /* LWIP_DHCP */
119 return 1;
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 );
132 #if LWIP_DHCP
133 if ( pInfo -> dhcp_enabled ) {
134 if ( !pNetIF -> dhcp ) dhcp_start ( pNetIF );
135 } else {
136 if ( pNetIF -> dhcp ) dhcp_stop ( pNetIF );
137 } /* end else */
138 #endif /* LWIP_DHCP */
139 return 1;
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 {
149 int m_EventFlag;
150 unsigned long m_EventMask;
151 iop_sys_clock_t m_Clock;
153 } AlarmData;
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;
163 } /* end _alarm */
165 static void TimerThread ( void* apArg ) {
167 AlarmData lTCPData;
168 AlarmData lARPData;
169 iop_event_t lEvent;
171 lEvent.attr = 0;
172 lEvent.bits = 0;
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 );
183 while ( 1 ) {
185 unsigned long lRes;
187 WaitEventFlag ( lTCPData.m_EventFlag, ALARM_MSK, WEF_CLEAR | WEF_OR, &lRes );
189 #if LWIP_TCP
190 if ( lRes & ALARM_TCP ) tcp_tmr ();
191 #endif
192 if ( lRes & ALARM_ARP ) etharp_tmr ();
194 } /* end while */
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 {
210 struct pbuf* pInput;
211 struct netif* pNetIF;
212 } InputMSG;
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;
233 int iFlags;
235 CpuSuspendIntr ( &iFlags );
236 u8FirstMSG = GetNextMSGQueueIndex ( u8FirstMSG );
237 CpuResumeIntr ( iFlags );
239 switch ( ( ( struct eth_hdr* )( pInput -> payload ) ) -> type ) {
241 case ETHTYPE_IP:
242 etharp_ip_input ( pNetIF, pInput );
243 pbuf_header ( pInput, -14 );
244 ip_input ( pInput, pNetIF );
245 break;
247 case ETHTYPE_ARP:
248 etharp_arp_input (
249 pNetIF, ( struct eth_addr* )&pNetIF -> hwaddr, pInput
251 default: pbuf_free ( pInput );
253 } /* end switch */
255 } /* end InputCB */
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.
264 InputMSG* pIMSG;
265 struct tcpip_msg* pMSG;
267 if ( IsMessageBoxFull ( g_TCPIPMBox ) || IsMSGQueueFull () ) {
268 pbuf_free ( pInput );
269 return ERR_OK;
270 } /* end if */
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 );
279 if ( !pMSG ) {
280 pbuf_free ( pInput );
281 return ERR_MEM;
282 } /* end if */
284 pMSG -> type = TCPIP_MSG_CALLBACK;
285 pMSG -> msg.cb.f = InputCB;
286 pMSG -> msg.cb.ctx = pIMSG;
287 PostInputMSG ( g_TCPIPMBox, pMSG );
289 return ERR_OK;
291 } /* end ps2ip_input */
293 void ps2ip_Stub ( void ) {
295 } /* end ps2ip_Stub */
297 int ps2ip_ShutDown ( void ) {
299 return 1;
301 } /* end ps2ip_ShutDown */
302 #if LWIP_HAVE_LOOPIF
303 static void AddLoopIF ( void ) {
305 IPAddr IP;
306 IPAddr NM;
307 IPAddr GW;
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 ) {
319 sys_sem_t lSema;
321 RegisterLibraryEntries ( &_exp_ps2ip );
323 mem_init ();
324 memp_init ();
325 pbuf_init ();
326 netif_init ();
328 lSema = sys_sem_new ( 0 );
329 tcpip_init ( ( void ( * )( void* ) )SignalSema, ( void* )lSema );
330 WaitSema ( lSema );
331 sys_sem_free ( lSema );
332 #if LWIP_HAVE_LOOPIF
333 AddLoopIF ();
334 #endif /* LWIP_HAVE_LOOPIF */
335 InitTimer ();
337 return MODULE_RESIDENT_END;
339 } /* end _start */
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
350 int iThreadID;
352 iThreadID = CreateThread ( &Info );
354 if ( iThreadID < 0 ) return -1;
356 StartThread ( iThreadID, pvArg );
358 return iThreadID;
360 } /* end sys_thread_new */
362 sys_mbox_t sys_mbox_new ( void ) {
364 sys_mbox_t pMBox;
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;
375 return pMBox;
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 ) {
394 sys_prot_t Flags;
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;
410 } /* end while */
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 ) {
423 sys_prot_t Flags;
424 u32_t u32Time = 0;
426 CpuSuspendIntr ( &Flags );
428 while ( IsMessageBoxEmpty ( pMBox ) ) {
430 u32_t u32WaitTime;
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;
442 goto end;
443 } /* end if */
445 u32Time += u32WaitTime;
446 u32Timeout -= u32WaitTime;
448 } /* end while */
450 *ppvMSG = pMBox -> apvMSG[ pMBox -> u16First ];
451 pMBox -> u16First = GenNextMBoxIndex ( pMBox -> u16First );
453 if ( pMBox -> iWaitPost > 0 ) SignalSema ( pMBox -> Mail );
454 end:
455 CpuResumeIntr ( Flags );
457 return u32Time;
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 };
464 int retVal;
466 retVal = CreateSema ( &lSema );
468 if ( retVal <= 0 ) retVal = SYS_SEM_NULL;
470 return retVal;
472 } /* end sys_sem_new */
474 u32_t sys_arch_sem_wait ( sys_sem_t aSema, u32_t aTimeout ) {
476 if ( !aTimeout )
477 return WaitSema ( aSema );
478 else {
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 );
488 --aTimeout;
489 } else aTimeout = SYS_ARCH_TIMEOUT;
491 } /* end else */
493 return aTimeout;
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 */