PS2SDK
PS2 Homebrew Libraries
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 
16 static SifRpcClientData_t EEClient;
17 static union{
18  s32 result;
19  struct NetManEEInitResult EEInitResult;
20  u8 buffer[64];
21 } SifRpcRxBuffer;
22 static union{
23  s32 state;
24  u8 buffer[64];
25 } SifRpcTxBuffer;
26 
27 //Data for IOP -> EE transfers
28 static unsigned short int EEFrameBufferWrPtr, NumFramesInQueue;
29 static SifDmaTransfer_t dmatReqs[NETMAN_FRAME_GROUP_SIZE*2];
30 
31 static int NetManIOSemaID = -1;
32 
34  void *handle;
35  void *payload;
36  u32 length;
37 };
38 
39 //Data for SPEED -> IOP transfers
40 static struct NetManPacketBuffer pbufs[NETMAN_RPC_BLOCK_SIZE];
41 static u8 *FrameBuffer = NULL;
42 static struct NetManBD *FrameBufferStatus = NULL;
43 static struct NetManBD *EEFrameBufferStatus = NULL;
44 
45 int 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 
86 void 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 
107 void 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.
116 void *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 
137 void NetManRpcNetProtStackFreeRxPacket(void *packet)
138 {
139  ((struct NetManPacketBuffer*)packet)->handle = NULL;
140 }
141 
142 //Only one thread can enter this critical section!
143 static 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 
176 static 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!
184 static 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.
233 void NetManRpcProtStackEnQRxPacket(void *packet)
234 {
235  EnQFrame(((struct NetManPacketBuffer*)packet)->payload, ((struct NetManPacketBuffer*)packet)->length);
236 }
thbase.h
iop_sema_t
Definition: thsemap.h:38
sifman.h
sysclib.h
ENOMEM
#define ENOMEM
Definition: errno.h:43
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
netman.h
thsemap.h
netman_rpc.h
t_SifDmaTransfer
Definition: sifdma.h:52
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
t_SifRpcClientData
Definition: sifrpc-common.h:134
NetManBD
Definition: netman_rpc.h:82
NetManPacketBuffer
Definition: rpc_client.c:33
intrman.h
thevent.h
_iop_sys_clock
Definition: thbase.h:87
NetManEEInitResult
Definition: netman_rpc.h:33
errno.h