PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
hub.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
13static void hubStatusChangeCallback(UsbdIoRequest_t *req);
14static int hubDrvConnect(int devId);
15static int hubDrvDisconnect(int devId);
16static int hubDrvProbe(int devId);
17
18static UsbdUsbHub_t *hubBufferList = NULL;
19static void *hubBufferListMemoryBuffer = NULL;
20static int hubAllocatedCount = 0;
21static sceUsbdLddOps usbHubDriver = {
22 NULL,
23 NULL,
24 "hub",
25 &hubDrvProbe,
26 &hubDrvConnect,
27 &hubDrvDisconnect,
28 0u,
29 0u,
30 0u,
31 0u,
32 0u,
33 NULL,
34};
35
36static UsbdUsbHub_t *allocHubBuffer(void)
37{
38 UsbdUsbHub_t *res;
39
40 if ( !hubBufferList )
41 {
42 return NULL;
43 }
44 res = hubBufferList;
45 hubBufferList = hubBufferList->m_next;
46 res->m_desc.bDescriptorType = 0;
47 res->m_statusIoReq.m_busyFlag = 0;
48 res->m_controlIoReq.m_busyFlag = 0;
49 res->m_curAllocatedCount = hubAllocatedCount;
50 hubAllocatedCount += 1;
51 return res;
52}
53
54static void freeHubBuffer(UsbdUsbHub_t *hub)
55{
56 hub->m_next = hubBufferList;
57 hubBufferList = hub;
58}
59
60static UsbdDevice_t *fetchPortElemByNumber(UsbdDevice_t *hub, int port)
61{
62 UsbdDevice_t *res;
63
64 for ( res = hub->m_childListStart; res && port > 0; port -= 1, res = res->m_next )
65 {
66 }
67 return res;
68}
69
70static void getHubStatusChange(UsbdUsbHub_t *dev)
71{
72 if ( dev->m_statusIoReq.m_busyFlag )
73 {
74 dbg_printf("getHubStatusChange: StatusChangeEP IoReq is busy!\n");
75 return;
76 }
77 attachIoReqToEndpoint(
78 dev->m_statusChangeEp,
79 &dev->m_statusIoReq,
80 dev->m_statusChangeInfo,
81 (int)(dev->m_numChildDevices + 7) >> 3,
82 hubStatusChangeCallback);
83}
84
85static void hubControlTransfer(
86 UsbdUsbHub_t *hubDev,
87 u8 requestType,
88 u8 request,
89 u16 value,
90 u16 index,
91 u16 length,
92 void *destData,
93 void *callback,
94 const char *fromfunc)
95{
96 if ( hubDev->m_controlIoReq.m_busyFlag )
97 {
98 dbg_printf("ERROR: hubControlTransfer %p: ioReq busy\n", hubDev);
99 printf("hub_control_transfer: busy - %s\n", fromfunc);
100 }
101 else
102 doControlTransfer(
103 hubDev->m_controlEp, &hubDev->m_controlIoReq, requestType, request, value, index, length, destData, callback);
104}
105
106static void hubGetPortStatusCallback(UsbdIoRequest_t *req)
107{
108 UsbdUsbHub_t *dev;
109 int feature;
110 UsbdDevice_t *port;
111
112 dev = (UsbdUsbHub_t *)req->m_userCallbackArg;
113 feature = -1;
114 if ( req->m_resultCode != USB_RC_OK )
115 {
116 dbg_printf("HubGetPortStatusCallback res %d\n", req->m_resultCode);
117 return;
118 }
119 dbg_printf("port status change: %d: %08X\n", dev->m_portCounter, dev->m_portStatusChange);
120 if ( (dev->m_portStatusChange & BIT(C_PORT_CONNECTION)) != 0 )
121 {
122 port = fetchPortElemByNumber(dev->m_controlEp->m_correspDevice, dev->m_portCounter);
123 if ( !port )
124 {
125 hubStatusChangeCallback(&dev->m_statusIoReq);
126 return;
127 }
128 if ( port->m_deviceStatus >= (unsigned int)DEVICE_CONNECTED )
129 {
130 flushPort(port);
131 }
132 feature = C_PORT_CONNECTION;
133 }
134 else if ( (dev->m_portStatusChange & BIT(C_PORT_ENABLE)) != 0 )
135 {
136 feature = C_PORT_ENABLE;
137 }
138 else if ( (dev->m_portStatusChange & BIT(C_PORT_SUSPEND)) != 0 )
139 {
140 feature = C_PORT_SUSPEND;
141 }
142 else if ( (dev->m_portStatusChange & BIT(C_PORT_OVER_CURRENT)) != 0 )
143 {
144 feature = C_PORT_OVER_CURRENT;
145 }
146 else if ( (dev->m_portStatusChange & BIT(C_PORT_RESET)) != 0 )
147 {
148 feature = C_PORT_RESET;
149 }
150 if ( feature >= 0 )
151 {
152 dev->m_portStatusChange &= ~BIT(feature);
153 hubControlTransfer(
154 dev,
155 USB_DIR_OUT | USB_RT_PORT,
156 USB_REQ_CLEAR_FEATURE,
157 feature & 0xFFFF,
158 dev->m_portCounter & 0xFFFF,
159 0,
160 NULL,
161 hubGetPortStatusCallback,
162 "clear_port_feature");
163 return;
164 }
165 port = fetchPortElemByNumber(dev->m_controlEp->m_correspDevice, dev->m_portCounter);
166 if ( port )
167 {
168 if ( (dev->m_portStatusChange & BIT(PORT_CONNECTION)) != 0 )
169 {
170 dbg_printf("Hub Port CCS\n");
171 if ( port->m_deviceStatus == DEVICE_NOTCONNECTED )
172 {
173 dbg_printf("resetting dev\n");
174 port->m_deviceStatus = DEVICE_CONNECTED;
175 addTimerCallback(&port->m_timer, (TimerCallback)hubResetDevice, port, 501);
176 return;
177 }
178 if ( port->m_deviceStatus == DEVICE_RESETPENDING && (dev->m_portStatusChange & BIT(PORT_ENABLE)) != 0 )
179 {
180 dbg_printf("hub port reset done, opening control EP\n");
181 port->m_deviceStatus = DEVICE_RESETCOMPLETE;
182 port->m_isLowSpeedDevice = (dev->m_portStatusChange & BIT(PORT_LOW_SPEED)) != 0;
183 if ( openDeviceEndpoint(port, NULL, 0) )
184 hubTimedSetFuncAddress(port);
185 else
186 dbg_printf("Can't open default control ep.\n");
187 dev->m_hubStatusCounter = 0;
188 }
189 }
190 else
191 {
192 dbg_printf("disconnected; flushing port\n");
193 flushPort(port);
194 }
195 }
196 hubStatusChangeCallback(&dev->m_statusIoReq);
197}
198
199static void hubDeviceResetCallback(UsbdIoRequest_t *arg)
200{
201 if ( arg->m_resultCode != USB_RC_OK )
202 {
203 dbg_printf("port reset err: %d\n", arg->m_resultCode);
204 return;
205 }
206 getHubStatusChange((UsbdUsbHub_t *)arg->m_userCallbackArg);
207}
208
209void hubResetDevicePort(UsbdDevice_t *dev)
210{
211 UsbdUsbHub_t *privDataField;
212
213 privDataField = (UsbdUsbHub_t *)dev->m_parent->m_privDataField;
214 privDataField->m_hubStatusCounter = dev->m_attachedToPortNo;
215 hubControlTransfer(
216 privDataField,
217 USB_DIR_OUT | USB_RT_PORT,
218 USB_REQ_SET_FEATURE,
219 PORT_RESET,
220 dev->m_attachedToPortNo,
221 0,
222 NULL,
223 hubDeviceResetCallback,
224 "hub_port_reset");
225}
226
227static void hubCalculateMagicPowerValue(UsbdUsbHub_t *hubDevice)
228{
229 UsbdDevice_t *dev;
230
231 dev = hubDevice->m_dev;
232 if ( (int)dev->m_magicPowerValue )
233 {
234 if ( (int)dev->m_magicPowerValue >= 0 && (int)dev->m_magicPowerValue < 6 && (int)dev->m_magicPowerValue >= 3 )
235 {
236 if ( (hubDevice->m_hubStatus & 1) != 0 )
237 dev->m_magicPowerValue = 4;
238 else
239 dev->m_magicPowerValue = 5;
240 }
241 }
242 else if ( hubDevice->m_isSelfPowered )
243 {
244 if ( (int)hubDevice->m_maxPower <= 0 )
245 dev->m_magicPowerValue = 2;
246 else
247 dev->m_magicPowerValue = 3;
248 }
249 else
250 {
251 dev->m_magicPowerValue = (int)hubDevice->m_maxPower > 0;
252 }
253}
254
255static void hubGetHubStatusCallback(UsbdIoRequest_t *req)
256{
257 UsbdUsbHub_t *dev;
258
259 dev = (UsbdUsbHub_t *)req->m_userCallbackArg;
260 if ( req->m_resultCode != USB_RC_OK )
261 {
262 return;
263 }
264 if ( (dev->m_hubStatusChange & BIT(C_HUB_LOCAL_POWER)) != 0 )
265 {
266 dev->m_hubStatusChange &= ~BIT(C_HUB_LOCAL_POWER);
267 hubControlTransfer(
268 dev,
269 USB_DIR_OUT | USB_RT_HUB,
270 USB_REQ_CLEAR_FEATURE,
271 C_HUB_LOCAL_POWER,
272 0,
273 0,
274 NULL,
275 hubGetHubStatusCallback,
276 "clear_hub_feature");
277 hubCalculateMagicPowerValue(dev);
278 }
279 else if ( (dev->m_hubStatusChange & BIT(C_HUB_OVER_CURRENT)) != 0 )
280 {
281 dev->m_hubStatusChange &= ~BIT(C_HUB_OVER_CURRENT);
282 hubControlTransfer(
283 dev,
284 USB_DIR_OUT | USB_RT_HUB,
285 USB_REQ_CLEAR_FEATURE,
286 C_HUB_OVER_CURRENT,
287 0,
288 0,
289 NULL,
290 hubGetHubStatusCallback,
291 "clear_hub_feature");
292 }
293 else
294 {
295 hubStatusChangeCallback(&dev->m_statusIoReq);
296 }
297}
298
299static void hubStatusChangeCallback(UsbdIoRequest_t *req)
300{
301 UsbdUsbHub_t *dev;
302 int port;
303
304 dev = (UsbdUsbHub_t *)req->m_userCallbackArg;
305 if ( req->m_resultCode != USB_RC_OK )
306 {
307 dbg_printf("hubStatusChangeCallback, iores %d\n", req->m_resultCode);
308 return;
309 }
310 if ( (dev->m_statusChangeInfo[0] & 1) != 0 )
311 {
312 dev->m_statusChangeInfo[0] &= ~1;
313 hubControlTransfer(
314 dev,
315 USB_DIR_IN | USB_RT_HUB,
316 USB_REQ_GET_STATUS,
317 0,
318 0,
319 4u,
320 &dev->m_hubStatus,
321 hubGetHubStatusCallback,
322 "scan_change_bitmap");
323 return;
324 }
325 port = dev->m_hubStatusCounter;
326 if ( port <= 0 )
327 {
328 port = 1;
329 if ( (int)dev->m_numChildDevices <= 0 )
330 {
331 getHubStatusChange(dev);
332 return;
333 }
334 while ( (((int)dev->m_statusChangeInfo[port >> 3] >> (port & 7)) & 1) == 0 )
335 {
336 port += 1;
337 if ( (int)dev->m_numChildDevices < port )
338 {
339 getHubStatusChange(dev);
340 return;
341 }
342 }
343 }
344 else if ( (((int)dev->m_statusChangeInfo[port >> 3] >> (port & 7)) & 1) == 0 )
345 {
346 getHubStatusChange(dev);
347 return;
348 }
349 dev->m_statusChangeInfo[port >> 3] &= ~BIT(port & 7);
350 dev->m_portCounter = port;
351 hubControlTransfer(
352 dev,
353 USB_DIR_IN | USB_RT_PORT,
354 USB_REQ_GET_STATUS,
355 0,
356 dev->m_portCounter,
357 4u,
358 &dev->m_portStatusChange,
359 hubGetPortStatusCallback,
360 "scan_change_bitmap");
361}
362
363static void hubSetPortPower(UsbdIoRequest_t *req)
364{
365 UsbdUsbHub_t *dev;
366
367 dev = (UsbdUsbHub_t *)req->m_userCallbackArg;
368 // there is no result to check if this is the first call for this hub
369 if ( (int)dev->m_portCounter > 0 && req->m_resultCode != USB_RC_OK )
370 {
371 return;
372 }
373 dev->m_portCounter += 1;
374 if ( ((int)dev->m_numChildDevices < (int)dev->m_portCounter) || usbConfig.m_maxPortsPerHub < (int)dev->m_portCounter )
375 getHubStatusChange(dev);
376 else
377 hubControlTransfer(
378 dev,
379 USB_DIR_OUT | USB_RT_PORT,
380 USB_REQ_SET_FEATURE,
381 PORT_POWER,
382 dev->m_portCounter,
383 0,
384 NULL,
385 hubSetPortPower,
386 "set_port_power");
387}
388
389static void hubSetupPorts(UsbdIoRequest_t *req)
390{
391 UsbdUsbHub_t *dev;
392 u32 i;
393
394 dev = (UsbdUsbHub_t *)req->m_userCallbackArg;
395 if ( req->m_resultCode != USB_RC_OK )
396 {
397 return;
398 }
399 hubCalculateMagicPowerValue(dev);
400
401 dev->m_hubStatusCounter = 0;
402 dev->m_portCounter = 0;
403 dev->m_numChildDevices = dev->m_desc.bNbrPorts;
404 for ( i = 0; (int)i < (int)dev->m_numChildDevices && (int)i < usbConfig.m_maxPortsPerHub; i += 1 )
405 {
406 if ( !attachChildDevice(dev->m_controlEp->m_correspDevice, i + 1) )
407 {
408 dev->m_numChildDevices = i;
409 break;
410 }
411 }
412 if ( (int)dev->m_numChildDevices > 0 )
413 hubSetPortPower(req);
414}
415
416static void hubCheckPorts(UsbdIoRequest_t *req)
417{
418 UsbdUsbHub_t *dev;
419
420 dev = (UsbdUsbHub_t *)req->m_userCallbackArg;
421 hubControlTransfer(
422 dev, USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_STATUS, 0, 0, 4u, &dev->m_hubStatus, hubSetupPorts, "get_hub_status");
423}
424
425static void hubCheckPortsCB(UsbdIoRequest_t *req)
426{
427 if ( req->m_resultCode != USB_RC_OK )
428 return;
429 hubCheckPorts(req);
430}
431
432static void hubCheckDeviceDesc(UsbdIoRequest_t *req)
433{
434 UsbdUsbHub_t *dev;
435
436 dev = (UsbdUsbHub_t *)req->m_userCallbackArg;
437 if ( req->m_resultCode != USB_RC_OK )
438 {
439 return;
440 }
441 if ( dev->m_desc.bDescriptorType == USB_DT_HUB )
442 hubCheckPorts(req); // we've got the descriptor already
443 else
444 hubControlTransfer(
445 dev,
446 USB_DIR_IN | USB_RT_HUB,
447 USB_REQ_GET_DESCRIPTOR,
448 USB_DT_HUB << 8,
449 0,
450 sizeof(UsbHubDescriptor),
451 &dev->m_desc,
452 hubCheckPortsCB,
453 "set_configuration_done");
454}
455
456static int hubDrvConnect(int devId)
457{
458 UsbdDevice_t *dev;
459 UsbConfigDescriptor *confDesc;
460 UsbInterfaceDescriptor *intfDesc;
461 UsbEndpointDescriptor *endpDesc;
462 UsbdUsbHub_t *hubDevice;
463 const UsbHubDescriptor *hubDesc;
464
465 dev = fetchDeviceById(devId);
466 if ( !dev )
467 return -1;
468 confDesc = (UsbConfigDescriptor *)doGetDeviceStaticDescriptor(devId, NULL, USB_DT_CONFIG);
469 if ( !confDesc || confDesc->bNumInterfaces != 1 )
470 return -1;
471 intfDesc = (UsbInterfaceDescriptor *)doGetDeviceStaticDescriptor(devId, confDesc, USB_DT_INTERFACE);
472 if ( !intfDesc )
473 {
474 return -1;
475 }
476 if ( intfDesc->bNumEndpoints != 1 )
477 {
478 return -1;
479 }
480 endpDesc = (UsbEndpointDescriptor *)doGetDeviceStaticDescriptor(devId, intfDesc, USB_DT_ENDPOINT);
481 if ( !endpDesc )
482 {
483 return -1;
484 }
485 if ( (endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN )
486 return -1;
487 if ( (endpDesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT )
488 return -1;
489 hubDesc = (UsbHubDescriptor *)doGetDeviceStaticDescriptor(devId, endpDesc, USB_DT_HUB);
490 hubDevice = allocHubBuffer();
491 if ( !hubDevice )
492 return -1;
493 dev->m_privDataField = hubDevice;
494 hubDevice->m_dev = dev;
495 hubDevice->m_controlEp = dev->m_endpointListStart;
496 hubDevice->m_statusChangeEp = doOpenEndpoint(dev, endpDesc, 0);
497 if ( !hubDevice->m_statusChangeEp )
498 {
499 freeHubBuffer(hubDevice);
500 return -1;
501 }
502 hubDevice->m_statusIoReq.m_userCallbackArg = hubDevice;
503 hubDevice->m_controlIoReq.m_userCallbackArg = hubDevice;
504 hubDevice->m_maxPower = confDesc->maxPower;
505 hubDevice->m_isSelfPowered = (confDesc->bmAttributes >> 6) & 1;
506 hubCalculateMagicPowerValue(hubDevice);
507 if ( hubDesc )
508 {
509 bcopy(
510 hubDesc,
511 &hubDevice->m_desc,
512 (hubDesc->bLength < sizeof(UsbHubDescriptor)) ? hubDesc->bLength : sizeof(UsbHubDescriptor));
513 }
514 hubControlTransfer(
515 hubDevice,
516 USB_DIR_OUT | USB_RECIP_DEVICE,
517 USB_REQ_SET_CONFIGURATION,
518 confDesc->bConfigurationValue,
519 0,
520 0,
521 NULL,
522 hubCheckDeviceDesc,
523 "hub_attach");
524 return 0;
525}
526
527static int hubDrvDisconnect(int devId)
528{
529 UsbdDevice_t *dev;
530
531 dev = fetchDeviceById(devId);
532 if ( !dev )
533 return -1;
534 freeHubBuffer((UsbdUsbHub_t *)dev->m_privDataField);
535 return 0;
536}
537
538static int hubDrvProbe(int devId)
539{
540 const UsbDeviceDescriptor *devDesc;
541
542 devDesc = (const UsbDeviceDescriptor *)doGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE);
543 return devDesc && devDesc->bDeviceClass == USB_CLASS_HUB && devDesc->bNumConfigurations == 1;
544}
545
546int initHubDriver(void)
547{
548 int needMem;
549 UsbdUsbHub_t *hub;
550 int i;
551 void *OldGP;
552
553 needMem = usbConfig.m_maxHubDevices * sizeof(UsbdUsbHub_t);
554 hubBufferList = (UsbdUsbHub_t *)AllocSysMemoryWrap(needMem);
555 if ( !hubBufferList )
556 {
557 dbg_printf("ERROR: unable to alloc hub buffer\n");
558 return -1;
559 }
560 hub = hubBufferList;
561 hubBufferListMemoryBuffer = hub;
562 bzero(hubBufferList, needMem);
563 usbConfig.m_allocatedSize_unused += needMem;
564 for ( i = 0; i < usbConfig.m_maxHubDevices; i += 1 )
565 {
566 hub[i].m_next = (i < usbConfig.m_maxHubDevices - 1) ? &hub[i + 1] : NULL;
567 }
568#if USE_GP_REGISTER
569 OldGP = GetGP();
570#else
571 OldGP = NULL;
572#endif
573 doRegisterDriver(&usbHubDriver, OldGP);
574 return 0;
575}
576
577void deinitHubDriver(void)
578{
579 doUnregisterDriver(&usbHubDriver);
580 FreeSysMemoryWrap(hubBufferListMemoryBuffer);
581}
#define USB_RC_OK
Definition usbd.h:238