Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions iop/usb/usbd_mini/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,35 @@
# Licenced under Academic Free License version 2.0
# Review ps2sdk README & LICENSE files for further details.

IOP_SRC_DIR = $(PS2SDKSRC)/iop/usb/usbd/src/
# usbd_mini: FreeUsbd implementation (pre-b1f7ff96), not the SCE rewrite in ../usbd.
# See README.md / ps2sdk issue #908.

IOP_PREFER_GPOPT = 16384

IOP_CFLAGS += -DMINI_DRIVER
IOP_IMPORT_INCS += usb/usbd/

include $(PS2SDKSRC)/iop/usb/usbd/Makefile
IOP_IMPORT_INCS += \
system/intrman \
system/loadcore \
system/stdio \
system/sysclib \
system/sysmem \
system/threadman \
usb/usbd

IOP_OBJS = \
hcd.o \
hub.o \
interface.o \
mem.o \
usbd.o \
usbio.o \
driver.o \
usbd_v12_stubs.o \
imports.o \
exports.o

include $(PS2SDKSRC)/Defs.make
include $(PS2SDKSRC)/iop/Rules.bin.make
include $(PS2SDKSRC)/iop/Rules.make
include $(PS2SDKSRC)/iop/Rules.release
16 changes: 16 additions & 0 deletions iop/usb/usbd_mini/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# usbd_mini — FreeUsbd (pre-rewrite)

This module is built from the **FreeUsbd** sources last known good before
ps2sdk commit `b1f7ff96` (“USBD feature update”, 2024-09-04), i.e. tree
`2dc6b32f`.

The full `iop/usb/usbd` tree remains the SCE rewrite (usbd 1.2 with HID report
descriptors and multi-isochronous). `usbd_mini` is what OPL and other BDM USB
loaders embed; restoring FreeUsbd here fixes Crash Bandicoot: Wrath of Cortex
over USB on hardware while leaving the rewrite available for other consumers.

Export table stays **usbd 1.2** with stubs for `usbdReboot`,
`sceUsbdGetReportDescriptor`, and `sceUsbdMultiIsochronousTransfer`
(`USB_RC_NOSUPPORT` / no-op). Mass storage does not use those entry points.

See: https://github.com/ps2dev/ps2sdk/issues/908
283 changes: 283 additions & 0 deletions iop/usb/usbd_mini/src/driver.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
/*
# _____ ___ ____ ___ ____
# ____| | ____| | | |____|
# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
#-----------------------------------------------------------------------
# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
# Licenced under Academic Free License version 2.0
# Review ps2sdk README & LICENSE files for further details.
*/

/**
* @file
* USB Driver function prototypes and constants.
*/

#include "usbdpriv.h"
#include "driver.h"
#include "mem.h"
#include "hub.h"

#include "defs.h"
#include "stdio.h"
#include "sysclib.h"
#include "thbase.h"
#include "thevent.h"
#include "intrman.h"

sceUsbdLddOps *drvListStart = NULL, *drvListEnd = NULL;
sceUsbdLddOps *drvAutoLoader = NULL;
IoRequest *cbListStart = NULL, *cbListEnd = NULL;

int callbackEvent;
int callbackTid = -1;

int callUsbDriverFunc(int (*func)(int devId), int devId, void *gp)
{
int res;

if (func) {
usbdUnlock();
#if USE_GP_REGISTER
ChangeGP(gp);
#else
(void)gp;
#endif
res = func(devId);
#if USE_GP_REGISTER
SetGP(&_gp);
#endif
usbdLock();
return res;
} else
return 0;
}

void probeDeviceTree(Device *tree, sceUsbdLddOps *drv)
{
Device *curDevice;
for (curDevice = tree->childListStart; curDevice != NULL; curDevice = curDevice->next)
if (curDevice->deviceStatus == DEVICE_READY) {
if (curDevice->devDriver == NULL) {
if (callUsbDriverFunc(drv->probe, curDevice->id, drv->gp) != 0) {
curDevice->devDriver = drv;
callUsbDriverFunc(drv->connect, curDevice->id, drv->gp);
}
} else if (curDevice->childListStart)
probeDeviceTree(curDevice, drv);
}
}

int doRegisterDriver(sceUsbdLddOps *drv, void *drvGpSeg)
{
if (drv->next || drv->prev)
return USB_RC_BUSY;
if (drvListStart == drv)
return USB_RC_BUSY;

if (!drv->name)
return USB_RC_BADDRIVER;
if (drv->reserved1 || drv->reserved2)
return USB_RC_BADDRIVER;

drv->gp = drvGpSeg;

drv->prev = drvListEnd;
if (drvListEnd)
drvListEnd->next = drv;
else
drvListStart = drv;
drvListEnd = drv;

if (drv->probe)
probeDeviceTree(memPool.deviceTreeRoot, drv);

return 0;
}

int doRegisterAutoLoader(sceUsbdLddOps *drv, void *drvGpSeg)
{
if (drv->next || drv->prev)
return USB_RC_BADDRIVER;
if (!drv->name)
return USB_RC_BADDRIVER;
if (drv->reserved1 || drv->reserved2)
return USB_RC_BADDRIVER;

if (drvAutoLoader != NULL)
return USB_RC_BUSY;

drv->gp = drvGpSeg;

drvAutoLoader = drv;

if (drv->probe)
probeDeviceTree(memPool.deviceTreeRoot, drv);

return 0;
}

void disconnectDriver(Device *tree, sceUsbdLddOps *drv)
{
Endpoint *ep, *nextEp;
if (tree->devDriver == drv) {
if (tree->endpointListStart) {
ep = tree->endpointListStart->next;

while (ep) {
nextEp = ep->next;
removeEndpointFromDevice(tree, ep);
ep = nextEp;
}
}
tree->devDriver = NULL;
tree->privDataField = NULL;
}

for (tree = tree->childListStart; tree != NULL; tree = tree->next)
disconnectDriver(tree, drv);
}

int doUnregisterAutoLoader(void)
{
drvAutoLoader = NULL;
return 0;
}

int doUnregisterDriver(sceUsbdLddOps *drv)
{
sceUsbdLddOps *pos;
for (pos = drvListStart; pos != NULL; pos = pos->next)
if (pos == drv) {
if (drv->next)
drv->next->prev = drv->prev;
else
drvListEnd = drv->prev;

if (drv->prev)
drv->prev->next = drv->next;
else
drvListStart = drv->next;

disconnectDriver(memPool.deviceTreeRoot, drv);
return 0;
}
return USB_RC_BADDRIVER;
}

void connectNewDevice(Device *dev)
{
sceUsbdLddOps *drv;
dbg_printf("searching driver for dev %d, FA %02X\n", dev->id, dev->functionAddress);
for (drv = drvListStart; drv != NULL; drv = drv->next)
if (callUsbDriverFunc(drv->probe, dev->id, drv->gp) != 0) {
dev->devDriver = drv;
dbg_printf("Driver found (%s)\n", drv->name);
callUsbDriverFunc(drv->connect, dev->id, drv->gp);
return;
}

// No driver found yet. Call autoloader.
if (drvAutoLoader != NULL) {
drv = drvAutoLoader;

if (callUsbDriverFunc(drv->probe, dev->id, drv->gp) != 0) {
dev->devDriver = drv;
dbg_printf("(autoloader) Driver found (%s)\n", drv->name);
callUsbDriverFunc(drv->connect, dev->id, drv->gp);
return;
}
}

dbg_printf("no driver found\n");
}

void signalCallbackThreadFunc(IoRequest *req)
{
int intrStat;

CpuSuspendIntr(&intrStat);

req->prev = cbListEnd;
req->next = NULL;
if (cbListEnd)
cbListEnd->next = req;
else
cbListStart = req;
cbListEnd = req;

CpuResumeIntr(intrStat);

SetEventFlag(callbackEvent, 1);
}

void callbackThreadFunc(void *arg)
{
u32 eventRes;
int intrStat;
IoRequest *req;
IoRequest reqCopy;

(void)arg;

while (1) {
WaitEventFlag(callbackEvent, 1, WEF_CLEAR | WEF_OR, &eventRes);
do {
CpuSuspendIntr(&intrStat);

req = cbListStart;
if (req) {
if (req->next)
req->next->prev = req->prev;
else
cbListEnd = req->prev;

if (req->prev)
req->prev->next = req->next;
else
cbListStart = req->next;
}
CpuResumeIntr(intrStat);

if (req) {
memcpy(&reqCopy, req, sizeof(IoRequest));
usbdLock();
freeIoRequest(req);
usbdUnlock();

if (reqCopy.userCallbackProc) {
#if USE_GP_REGISTER
SetGP(req->gpSeg);
#endif
reqCopy.userCallbackProc(reqCopy.resultCode, reqCopy.transferedBytes, reqCopy.userCallbackArg);
#if USE_GP_REGISTER
SetGP(&_gp);
#endif
}
}
} while (req);
}
}

int initCallbackThread(void)
{
iop_event_t event;
iop_thread_t thread;

event.attr = event.option = event.bits = 0;
callbackEvent = CreateEventFlag(&event);

thread.attr = TH_C;
thread.option = 0;
thread.thread = callbackThreadFunc;
#ifndef MINI_DRIVER
thread.stacksize = 0x4000; // 16KiB
#else
thread.stacksize = 0x0800; // 2KiB
#endif
thread.priority = usbConfig.cbThreadPrio;
callbackTid = CreateThread(&thread);
StartThread(callbackTid, NULL);

return 0;
}
31 changes: 31 additions & 0 deletions iop/usb/usbd_mini/src/driver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
# _____ ___ ____ ___ ____
# ____| | ____| | | |____|
# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
#-----------------------------------------------------------------------
# Copyright 2001-2004, ps2dev - http://www.ps2dev.org
# Licenced under Academic Free License version 2.0
# Review ps2sdk README & LICENSE files for further details.
*/

/**
* @file
* USB Driver function prototypes and constants.
*/

#ifndef __DRIVER_H__
#define __DRIVER_H__

#include "usbdpriv.h"

int callUsbDriverFunc(int (*func)(int devId), int devId, void *gp);
int doRegisterDriver(sceUsbdLddOps *drv, void *drvGpSeg);
int doRegisterAutoLoader(sceUsbdLddOps *drv, void *drvGpSeg);
int doUnregisterAutoLoader(void);
int doUnregisterDriver(sceUsbdLddOps *drv);
void signalCallbackThreadFunc(IoRequest *req);
void callbackThreadFunc(void *arg);
void connectNewDevice(Device *dev);
int initCallbackThread(void);

#endif //__DRIVER_H__
25 changes: 25 additions & 0 deletions iop/usb/usbd_mini/src/exports.tab
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**/

DECLARE_EXPORT_TABLE(usbd, 1, 2)
DECLARE_EXPORT(_start)
DECLARE_EXPORT(_retonly)
DECLARE_EXPORT(usbdReboot)
DECLARE_EXPORT(_retonly)
DECLARE_EXPORT(sceUsbdRegisterLdd)
/*05*/ DECLARE_EXPORT(sceUsbdUnregisterLdd)
DECLARE_EXPORT(sceUsbdScanStaticDescriptor)
DECLARE_EXPORT(sceUsbdSetPrivateData)
DECLARE_EXPORT(sceUsbdGetPrivateData)
DECLARE_EXPORT(sceUsbdOpenPipe)
/*10*/ DECLARE_EXPORT(sceUsbdClosePipe)
DECLARE_EXPORT(sceUsbdTransferPipe)
DECLARE_EXPORT(sceUsbdOpenPipeAligned)
DECLARE_EXPORT(sceUsbdGetDeviceLocation)
DECLARE_EXPORT(sceUsbdRegisterAutoloader)
/*15*/ DECLARE_EXPORT(sceUsbdUnregisterAutoloader)
DECLARE_EXPORT(sceUsbdChangeThreadPriority)
DECLARE_EXPORT(sceUsbdGetReportDescriptor)
DECLARE_EXPORT(sceUsbdMultiIsochronousTransfer)
END_EXPORT_TABLE

void _retonly() {}
Loading