PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
rpc_client.c
1#include <errno.h>
2#include <intrman.h>
3#include <limits.h>
4#include <sifcmd.h>
5#include <sifman.h>
6#include <sysclib.h>
7#include <thbase.h>
8#include <thevent.h>
9#include <thsemap.h>
10#include <netman.h>
11#include <netman_rpc.h>
12
13#include "internal.h"
14#include "rpc_client.h"
15
16static SifRpcClientData_t EEClient;
17static union{
18 s32 result;
19 struct NetManEEInitResult EEInitResult;
20 u8 buffer[64];
21} SifRpcRxBuffer;
22static union{
23 s32 state;
24 u8 buffer[64];
25} SifRpcTxBuffer;
26
27//Data for IOP -> EE transfers
28static unsigned short int EEFrameBufferWrPtr, NumFramesInQueue;
29static SifDmaTransfer_t dmatReqs[NETMAN_FRAME_GROUP_SIZE*2];
30
31static int NetManIOSemaID = -1;
32
34 void *handle;
35 void *payload;
36 u32 length;
37};
38
39//Data for SPEED -> IOP transfers
40static struct NetManPacketBuffer pbufs[NETMAN_RPC_BLOCK_SIZE];
41static u8 *FrameBuffer = NULL;
42static struct NetManBD *FrameBufferStatus = NULL;
43static struct NetManBD *EEFrameBufferStatus = NULL;
44
45int NetManInitRPCClient(void)
46{
47 static const char NetManID[] = "NetMan";
48 iop_sema_t sema;
49 int result;
50
51 if(FrameBuffer == NULL) FrameBuffer = malloc(NETMAN_RPC_BLOCK_SIZE * NETMAN_MAX_FRAME_SIZE);
52 if(FrameBufferStatus == NULL) FrameBufferStatus = malloc(NETMAN_RPC_BLOCK_SIZE * sizeof(struct NetManBD));
53
54 if(FrameBuffer != NULL && FrameBufferStatus != NULL)
55 {
56 int i;
57
58 memset(FrameBuffer, 0, NETMAN_RPC_BLOCK_SIZE * NETMAN_MAX_FRAME_SIZE);
59 memset(FrameBufferStatus, 0, NETMAN_RPC_BLOCK_SIZE * sizeof(struct NetManBD));
60 EEFrameBufferWrPtr = 0;
61 NumFramesInQueue = 0;
62
63 for(i = 0; i < NETMAN_RPC_BLOCK_SIZE; i++) //Mark all descriptors as "in-use", until the EE-side allocates buffers.
64 FrameBufferStatus[i].length = USHRT_MAX;
65
66 while((result=sceSifBindRpc(&EEClient, NETMAN_RPC_NUMBER, 0))<0 || EEClient.server==NULL) DelayThread(500);
67
68 if((result=sceSifCallRpc(&EEClient, NETMAN_EE_RPC_FUNC_INIT, 0, &FrameBufferStatus, 4, &SifRpcRxBuffer, sizeof(struct NetManEEInitResult), NULL, NULL))>=0)
69 {
70 if((result=SifRpcRxBuffer.EEInitResult.result) == 0)
71 {
72 EEFrameBufferStatus = SifRpcRxBuffer.EEInitResult.FrameBufferStatus;
73
74 sema.attr = 0;
75 sema.option = (u32)NetManID;
76 sema.initial = 1;
77 sema.max = 1;
78 NetManIOSemaID = CreateSema(&sema);
79 }
80 }
81 }else result = -ENOMEM;
82
83 return result;
84}
85
86void NetManDeinitRPCClient(void)
87{
88 if(FrameBuffer != NULL)
89 {
90 free(FrameBuffer);
91 FrameBuffer = NULL;
92 }
93 if(FrameBufferStatus != NULL)
94 {
95 free(FrameBufferStatus);
96 FrameBufferStatus = NULL;
97 }
98 if(NetManIOSemaID >= 0)
99 {
100 DeleteSema(NetManIOSemaID);
101 NetManIOSemaID = -1;
102 }
103
104 memset(&EEClient, 0, sizeof(EEClient));
105}
106
107void NetManRpcToggleGlobalNetIFLinkState(int state)
108{
109 WaitSema(NetManIOSemaID);
110 SifRpcTxBuffer.state=state;
111 sceSifCallRpc(&EEClient, NETMAN_EE_RPC_FUNC_HANDLE_LINK_STATUS_CHANGE, 0, &SifRpcTxBuffer, sizeof(s32), NULL, 0, NULL, NULL);
112 SignalSema(NetManIOSemaID);
113}
114
115//For this implementation, a packet buffer is only taken if it is enqueued.
116void *NetManRpcNetProtStackAllocRxPacket(unsigned int length, void **payload)
117{
118 struct NetManPacketBuffer *result;
119 volatile const struct NetManBD *bd = &FrameBufferStatus[EEFrameBufferWrPtr];
120
121 //Wait for a free spot to appear in the ring buffer.
122 while(bd->length != 0) { }
123
124 //Allocation of PBUF descriptors is tied with the allocation of frame slots in the ring buffer by EnQ.
125 result = &pbufs[EEFrameBufferWrPtr];
126 result->handle = (void*)bd;
127 result->payload = &FrameBuffer[EEFrameBufferWrPtr * NETMAN_MAX_FRAME_SIZE];
128 result->length = length;
129
130 //The write pointer is not incremented here because the interface driver might discard the frame and free this allocated buffer.
131
132 *payload = result->payload;
133
134 return result;
135}
136
137void NetManRpcNetProtStackFreeRxPacket(void *packet)
138{
139 ((struct NetManPacketBuffer*)packet)->handle = NULL;
140}
141
142//Only one thread can enter this critical section!
143static int sendFramesToEE(int mode)
144{
145 int OldState;
146
147 if (NumFramesInQueue > 0)
148 {
149 int res;
150
151 dmatReqs[(NumFramesInQueue-1) * 2 + 1].attr = SIF_DMA_INT_O; //Mark the last entry to notify the receive thread of the incoming frame(s). This will stall SIF0.
152
153 //Transfer the frame over to the EE
154 do{
155 if (mode == 0)
156 CpuSuspendIntr(&OldState);
157 res = sceSifSetDma(dmatReqs, 2*NumFramesInQueue);
158 if (mode == 0)
159 CpuResumeIntr(OldState);
160
161 /* In interrupt mode, do not loop around sceSifSetDma as its status can only be updated by the SIF0 interrupt handler,
162 which would be blocked by this interrupt handler. */
163 if (mode != 0 && res == 0)
164 return -1;
165 }while(res == 0);
166
167 NumFramesInQueue = 0;
168 }
169
170 return 0;
171}
172
173//The SMAP Rx FIFO may only hold 16384 / 1518 = 10 frames. In 1ms, roughly 8 full-length frames can be transferred at 100Mbit within 1ms. 1ms = 36864 ticks.
174#define FRAME_GROUPING_INTERVAL 36864
175
176static unsigned int FrameSendCB(void *arg)
177{
178 (void)arg;
179
180 return(sendFramesToEE(1) == 0 ? 0 : FRAME_GROUPING_INTERVAL); //If sending failed, try again later.
181}
182
183//Only one thread can enter this critical section!
184static void EnQFrame(const void *frame, unsigned int length)
185{
186 SifDmaTransfer_t *dmat;
187 struct NetManBD *bd;
188 iop_sys_clock_t clock;
189
190 //Cancel any ongoing callbacks.
191 CancelAlarm(&FrameSendCB, NULL);
192
193 if (NumFramesInQueue >= NETMAN_FRAME_GROUP_SIZE)
194 { /* If there are already sufficient frames, the frames can be sent right away.
195 This may happen here if sending failed within the interrupt callback and there are more frames to send. */
196 sendFramesToEE(0);
197 }
198
199 //No need to wait for a free spot to appear, as Alloc already took care of that.
200 bd = &FrameBufferStatus[EEFrameBufferWrPtr];
201
202 //Record the frame length.
203 bd->length = length;
204
205 //Prepare DMA transfer.
206 dmat = &dmatReqs[NumFramesInQueue * 2];
207 dmat[0].src = (void*)frame;
208 dmat[0].dest = bd->payload;
209 dmat[0].size = (length + 3) & ~3;
210 dmat[0].attr = 0;
211
212 dmat[1].src = bd;
213 dmat[1].dest = &EEFrameBufferStatus[EEFrameBufferWrPtr];
214 dmat[1].size = sizeof(struct NetManBD);
215 dmat[1].attr = 0;
216 NumFramesInQueue++;
217
218 //Increase the write (IOP -> EE) pointer by one place.
219 EEFrameBufferWrPtr = (EEFrameBufferWrPtr + 1) % NETMAN_RPC_BLOCK_SIZE;
220
221 if (NumFramesInQueue >= NETMAN_FRAME_GROUP_SIZE)
222 { //If there are sufficient frames, the frames can be sent right away.
223 sendFramesToEE(0);
224 } else {
225 //Wait a while in case further frames can be grouped, to allow sceSifSetDma() to chain the requests together.
226 clock.lo = FRAME_GROUPING_INTERVAL;
227 clock.hi = 0;
228 SetAlarm(&clock, &FrameSendCB, NULL);
229 }
230}
231
232//Frames will be enqueued in the order that they were allocated.
233void NetManRpcProtStackEnQRxPacket(void *packet)
234{
235 EnQFrame(((struct NetManPacketBuffer*)packet)->payload, ((struct NetManPacketBuffer*)packet)->length);
236}
#define ENOMEM
Definition errno.h:43
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205