PS2SDK
PS2 Homebrew Libraries
usbd_main.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 #include "usbdpriv.h"
12 
13 #ifdef _IOP
14 IRX_ID("USB_driver", 2, 4);
15 #endif
16 // Based on the module from SCE SDK 3.1.0.
17 
18 static int usbdModuleUnload(void);
19 
20 extern struct irx_export_table _exp_usbd;
21 
22 static UsbdArgOption_t SupportedArgs[] = {
23  {"dev=", &usbConfig.m_maxDevices, NULL},
24  {"ed=", &usbConfig.m_maxEndpoints, NULL},
25  {"gtd=", &usbConfig.m_maxTransfDesc, NULL},
26  {"itd=", &usbConfig.m_maxIsoTransfDesc, NULL},
27  {"ioreq=", &usbConfig.m_maxIoReqs, NULL},
28  {"conf=", &usbConfig.m_maxStaticDescSize, NULL},
29  {"hub=", &usbConfig.m_maxHubDevices, NULL},
30  {"port=", &usbConfig.m_maxPortsPerHub, NULL},
31  {"thpri=", &usbConfig.m_hcdThreadPrio, &usbConfig.m_cbThreadPrio},
32  {"reportd=", &usbConfig.m_curDescNum, NULL},
33  {NULL, NULL, NULL}};
34 
35 UsbdMemoryPool_t *memPool = NULL;
36 UsbdKernelResources_t usbKernelResources = {-1, -1, -1, -1, -1};
37 UsbdIoRequest_t *cbListStart = NULL;
38 UsbdIoRequest_t *cbListEnd = NULL;
39 #ifndef MINI_DRIVER
40 UsbdConfig_t usbConfig = {
41  0x20,
42  0x40,
43  0x80,
44  0x80,
45  0x100,
46  0x200,
47  0x8,
48  0x8,
49  0x0,
50  0x1E,
51  0x24,
52  0x0,
53 };
54 #else
55 UsbdConfig_t usbConfig = {
56  0x10,
57  0x20,
58  0x40,
59  0x40,
60  0x100,
61  0x200,
62  0x4,
63  0x4,
64  0x0,
65  0x1E,
66  0x24,
67  0x0,
68 };
69 #endif
70 sceUsbdLddOps *drvListStart = NULL;
71 sceUsbdLddOps *drvListEnd = NULL;
72 sceUsbdLddOps *drvAutoLoader = NULL;
73 
74 static int usbdIntrHandler(void *arg)
75 {
76  const UsbdKernelResources_t *kernelResources;
77 
78  kernelResources = (UsbdKernelResources_t *)arg;
79  iSetEventFlag(kernelResources->m_hcdIrqEvent, 1u);
80  return 0;
81 }
82 
83 static void hcdIrqThread(void *arg)
84 {
85  u32 efres;
86 
87  (void)arg;
88  while ( 1 )
89  {
90  WaitEventFlag(usbKernelResources.m_hcdIrqEvent, 1u, WEF_OR | WEF_CLEAR, &efres);
91  usbdLock();
92  hcdProcessIntr();
93  EnableIntr(IOP_IRQ_USB);
94  PostIntrEnableFunction();
95  usbdUnlock();
96  }
97 }
98 
99 static void callbackThreadFunc(void *arg)
100 {
101  UsbdIoRequest_t *req;
102  UsbdIoRequest_t reqCopy;
103  u32 efres;
104  int state;
105 
106  (void)arg;
107  while ( 1 )
108  {
109  WaitEventFlag(usbKernelResources.m_callbackEvent, 1u, WEF_OR | WEF_CLEAR, &efres);
110  while ( 1 )
111  {
112  CpuSuspendIntr(&state);
113  req = cbListStart;
114  if ( req )
115  {
116  if ( req->m_next )
117  req->m_next->m_prev = req->m_prev;
118  else
119  cbListEnd = req->m_prev;
120  if ( req->m_prev )
121  req->m_prev->m_next = req->m_next;
122  else
123  cbListStart = req->m_next;
124  }
125  CpuResumeIntr(state);
126  if ( !req )
127  break;
128  bcopy(req, &reqCopy, sizeof(UsbdIoRequest_t));
129  usbdLock();
130  freeIoRequest(req);
131  usbdUnlock();
132  if ( reqCopy.m_userCallbackProc )
133  {
134 #if USE_GP_REGISTER
135  SetGP(reqCopy.m_gpSeg);
136 #endif
137  if ( reqCopy.m_req.bNumPackets )
138  reqCopy.m_userCallbackProcMultiIsochronous(reqCopy.m_resultCode, &reqCopy.m_req, reqCopy.m_userCallbackArg);
139  else
140  reqCopy.m_userCallbackProcRegular(reqCopy.m_resultCode, reqCopy.m_transferedBytes, reqCopy.m_userCallbackArg);
141 #if USE_GP_REGISTER
142  SetGP(_gp);
143 #endif
144  }
145  }
146  }
147 }
148 
149 void usbdReboot(int ac)
150 {
151  if ( (unsigned int)ac < 2 )
152  usbdRebootInner();
153 }
154 
155 static void ParseOptionInput(const UsbdArgOption_t *option, const char *arguments)
156 {
157  int value_1;
158  const char *p_1;
159  int value_2;
160  const char *p_2;
161 
162  value_1 = 0;
163  for ( p_1 = arguments; *p_1 && *p_1 != ','; p_1 += 1 )
164  {
165  if ( (unsigned int)(*p_1 - '0') >= 9 )
166  return;
167  value_1 = 10 * value_1 + (*p_1 - '0');
168  }
169  if ( option->value2 ? (*p_1 != ',') : (*p_1 == ',') )
170  return;
171  if ( arguments < p_1 )
172  *option->value = value_1;
173  if ( !option->value2 )
174  {
175  return;
176  }
177  value_2 = 0;
178  for ( p_2 = p_1 + 1; *p_2; p_2 += 1 )
179  {
180  if ( (unsigned int)(*p_2 - '0') >= 9 )
181  return;
182  value_2 = 10 * value_2 + (*p_2 - '0');
183  }
184  if ( p_1 + 1 < p_2 )
185  *option->value2 = value_2;
186 }
187 
188 int _start(int ac, char *av[], void *startaddr, ModuleInfo_t *mi)
189 {
190  int i;
191  UsbdArgOption_t *args_ptr;
192  const char *pParam;
193  char *pArgs;
194  iop_event_t ef;
195  iop_thread_t thparam;
196  iop_sema_t sema;
197  int intrstate;
198 
199  (void)startaddr;
200  if ( ac < 0 )
201  return usbdModuleUnload();
202  for ( i = 1; i < ac; i += 1 )
203  {
204  for ( args_ptr = SupportedArgs; args_ptr->param; args_ptr += 1 )
205  {
206  int j;
207  for ( j = 0, pParam = args_ptr->param, pArgs = av[i]; pParam[j] && pParam[j] == pArgs[j]; j += 1 )
208  {
209  }
210  if ( !pParam[j] )
211  {
212  ParseOptionInput(args_ptr, pArgs);
213  break;
214  }
215  }
216  }
217  dbg_printf("Intr handler...\n");
218  DisableIntr(IOP_IRQ_USB, &intrstate);
219  if ( RegisterIntrHandler(IOP_IRQ_USB, 1, usbdIntrHandler, &usbKernelResources) )
220  {
221  if ( intrstate == IOP_IRQ_USB )
222  {
223  EnableIntr(IOP_IRQ_USB);
224  return MODULE_NO_RESIDENT_END;
225  }
226  }
227  else
228  {
229  dbg_printf("library entries...\n");
230  if ( !RegisterLibraryEntries(&_exp_usbd) )
231  {
232  dbg_printf("Threads and events...\n");
233 
234  sema.attr = SA_THPRI;
235  sema.initial = 1;
236  sema.max = 1;
237  sema.option = 0;
238  usbKernelResources.m_usbdSema = CreateSema(&sema);
239  if ( usbKernelResources.m_usbdSema >= 0 )
240  {
241  ef.attr = EA_SINGLE;
242  ef.option = 0;
243  ef.bits = 0;
244  usbKernelResources.m_hcdIrqEvent = CreateEventFlag(&ef);
245  if ( usbKernelResources.m_hcdIrqEvent >= 0 )
246  {
247  dbg_printf("HCD thread...\n");
248  thparam.attr = TH_C;
249  thparam.thread = hcdIrqThread;
250 #ifndef MINI_DRIVER
251  thparam.stacksize = 0x4000; // 16KiB
252 #else
253  thparam.stacksize = 0x0800; // 2KiB
254 #endif
255  thparam.option = 0;
256  thparam.priority = usbConfig.m_hcdThreadPrio;
257  usbKernelResources.m_hcdTid = CreateThread(&thparam);
258  if ( usbKernelResources.m_hcdTid >= 0 && !StartThread(usbKernelResources.m_hcdTid, NULL) )
259  {
260  ef.attr = EA_SINGLE;
261  ef.option = 0;
262  ef.bits = 0;
263  usbKernelResources.m_callbackEvent = CreateEventFlag(&ef);
264  if ( usbKernelResources.m_callbackEvent >= 0 )
265  {
266  dbg_printf("Callback thread...\n");
267  thparam.attr = TH_C;
268  thparam.thread = callbackThreadFunc;
269 #ifndef MINI_DRIVER
270  thparam.stacksize = 0x4000; // 16KiB
271 #else
272  thparam.stacksize = 0x0800; // 2KiB
273 #endif
274  thparam.option = 0;
275  thparam.priority = usbConfig.m_cbThreadPrio;
276  usbKernelResources.m_callbackTid = CreateThread(&thparam);
277  if (
278  usbKernelResources.m_callbackTid >= 0 && !StartThread(usbKernelResources.m_callbackTid, NULL)
279  && usbdInitInner() >= 0 )
280  {
281  dbg_printf("Enabling interrupts...\n");
282  EnableIntr(IOP_IRQ_USB);
283  dbg_printf("Init done\n");
284 #if 0
285  return MODULE_REMOVABLE_END;
286 #else
287  if ( mi && ((mi->newflags & 2) != 0) )
288  mi->newflags |= 0x10;
289  return MODULE_RESIDENT_END;
290 #endif
291  }
292  }
293  }
294  }
295  }
296  }
297  else
298  {
299  dbg_printf("RegisterLibraryEntries failed\n");
300  }
301  if ( usbKernelResources.m_callbackTid > 0 )
302  DeleteThread(usbKernelResources.m_callbackTid);
303  if ( usbKernelResources.m_callbackEvent > 0 )
304  DeleteEventFlag(usbKernelResources.m_callbackEvent);
305  if ( usbKernelResources.m_hcdTid > 0 )
306  DeleteThread(usbKernelResources.m_hcdTid);
307  if ( usbKernelResources.m_hcdIrqEvent > 0 )
308  DeleteEventFlag(usbKernelResources.m_hcdIrqEvent);
309  if ( usbKernelResources.m_usbdSema > 0 )
310  DeleteSema(usbKernelResources.m_usbdSema);
311  ReleaseIntrHandler(IOP_IRQ_USB);
312  }
313  return MODULE_NO_RESIDENT_END;
314 }
315 
316 static int usbdModuleUnload(void)
317 {
318  int intrstate;
319 
320  if ( ReleaseLibraryEntries(&_exp_usbd) == 0 )
321  {
322  return MODULE_REMOVABLE_END;
323  }
324  DisableIntr(IOP_IRQ_USB, &intrstate);
325  ReleaseIntrHandler(IOP_IRQ_USB);
326  TerminateThread(usbKernelResources.m_hcdTid);
327  TerminateThread(usbKernelResources.m_callbackTid);
328  DeleteThread(usbKernelResources.m_hcdTid);
329  DeleteThread(usbKernelResources.m_callbackTid);
330  DeleteEventFlag(usbKernelResources.m_hcdIrqEvent);
331  DeleteEventFlag(usbKernelResources.m_callbackEvent);
332  DeleteSema(usbKernelResources.m_usbdSema);
333  deinitHcd();
334  deinitHubDriver();
335  return MODULE_NO_RESIDENT_END;
336 }
RegisterIntrHandler
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *arg), void *arg)
Definition: intrman.c:115
_ModuleInfo::newflags
u16 newflags
Definition: loadcore.h:36
ReleaseIntrHandler
int ReleaseIntrHandler(int irq)
Definition: intrman.c:157
_argOption
Definition: usbdpriv.h:35
iop_sema_t
Definition: thsemap.h:38
_usbdConfig
Definition: usbdpriv.h:42
DisableIntr
int DisableIntr(int irq, int *res)
Definition: intrman.c:385
_UsbDriver
Definition: usbd.h:47
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
_gp
void * _gp
EnableIntr
int EnableIntr(int irq)
Definition: intrman.c:336
irx_export_table
Definition: irx.h:90
_iop_thread
Definition: thbase.h:39
_usbdKernelResources
Definition: usbdpriv.h:308
usbdpriv.h
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
_memPool
Definition: usbdpriv.h:255
_ModuleInfo
Definition: loadcore.h:31
iop_event_t
Definition: thevent.h:37
EA_SINGLE
#define EA_SINGLE
Definition: thevent.h:33
_ioRequest
Definition: usbdpriv.h:82