diff --git a/iop/usb/usbd/Makefile b/iop/usb/usbd/Makefile index f48ba89ff17..f318316efbd 100644 --- a/iop/usb/usbd/Makefile +++ b/iop/usb/usbd/Makefile @@ -2,13 +2,27 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright ps2dev - http://www.ps2dev.org # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. -# IOP_CFLAGS += -DDEBUG - -IOP_OBJS = hcd.o hub.o interface.o mem.o usbd.o usbio.o driver.o imports.o exports.o +IOP_OBJS = \ + hub.o \ + mem.o \ + timer.o \ + endpoint.o \ + io_request.o \ + hub_resets.o \ + td_queue.o \ + hcd.o \ + usbd_sys.o \ + usbd_api.o \ + usbd_main.o \ + report_descriptor_init.o \ + device_driver.o \ + device.o \ + imports.o \ + exports.o IOP_PREFER_GPOPT = 16384 include $(PS2SDKSRC)/Defs.make diff --git a/iop/usb/usbd/include/usbd.h b/iop/usb/usbd/include/usbd.h index 65a394c6bb8..8cf542bc097 100644 --- a/iop/usb/usbd/include/usbd.h +++ b/iop/usb/usbd/include/usbd.h @@ -39,7 +39,7 @@ typedef struct u8 wHubCharacteristicsHb; u8 bPwrOn2PwrGood; u8 bHubContrCurrent; - u8 deviceRemovable[8]; // arbitrary number, depends on number of ports + u8 deviceRemovable[32]; // arbitrary number, depends on number of ports } UsbHubDescriptor; @@ -123,6 +123,23 @@ typedef struct u16 wData[1]; } UsbStringDescriptor; +typedef struct _usbHidDescriptorItem +{ + u8 bDescriptorType; + u8 wDescriptorLengthLb; + u8 wDescriptorLengthHb; +} UsbHidDescriptorItem; + +typedef struct _usbHidDescriptor +{ + u8 bLength; + u8 bDescriptorType; + u16 bcdHID; + u8 bCountryCode; + u8 bNumDescriptors; + UsbHidDescriptorItem items[]; +} UsbHidDescriptor; + typedef struct { u16 bLength : 11; @@ -291,7 +308,7 @@ int sceUsbdRegisterAutoloader(sceUsbdLddOps *drv); // Arbitrarily named int sceUsbdUnregisterAutoloader(void); // Arbitrarily named int sceUsbdChangeThreadPriority(int prio1, int prio2); -// these aren't implemented: +// These have been added in 1.2 export version int sceUsbdGetReportDescriptor(int devId, int cfgNum, int ifNum, void **desc, u32 *len); int sceUsbdMultiIsochronousTransfer(int pipeId, sceUsbdMultiIsochronousRequest *request, sceUsbdMultiIsochronousDoneCallback callback, void *cbArg); @@ -317,7 +334,7 @@ int sceUsbdMultiIsochronousTransfer(int pipeId, sceUsbdMultiIsochronousRequest * #define UsbGetReportDescriptor sceUsbdGetReportDescriptor #define UsbMultiIsochronousTransfer sceUsbdMultiIsochronousTransfer -#define usbd_IMPORTS_start DECLARE_IMPORT_TABLE(usbd, 1, 1) +#define usbd_IMPORTS_start DECLARE_IMPORT_TABLE(usbd, 1, 2) #define usbd_IMPORTS_end END_IMPORT_TABLE #define I_sceUsbdRegisterLdd DECLARE_IMPORT(4, sceUsbdRegisterLdd) diff --git a/iop/usb/usbd/src/device.c b/iop/usb/usbd/src/device.c new file mode 100644 index 00000000000..d728e5f75a9 --- /dev/null +++ b/iop/usb/usbd/src/device.c @@ -0,0 +1,427 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +static void fetchNextReportDescriptor(UsbdIoRequest_t *req); +static void requestDeviceDescriptor(UsbdIoRequest_t *req); +static void hubSetFuncAddress(UsbdEndpoint_t *ep); + +static const char *usbdVersionString = "Version 1.6.0"; + +void *doGetDeviceStaticDescriptor(int devId, void *data, u8 type) +{ + UsbdDevice_t *dev; + UsbDeviceDescriptor *descBuf; + + dev = fetchDeviceById(devId); + if ( !dev ) + { + return NULL; + } + descBuf = data ? (UsbDeviceDescriptor *)((u8 *)data + ((UsbDeviceDescriptor *)data)->bLength) : + (UsbDeviceDescriptor *)dev->m_staticDeviceDescPtr; + for ( ; descBuf->bLength >= 2u && (u8 *)descBuf < (u8 *)dev->m_staticDeviceDescEndPtr; + descBuf = (UsbDeviceDescriptor *)((u8 *)descBuf + descBuf->bLength) ) + { + if ( !type || descBuf->bDescriptorType == type ) + return descBuf; + } + return NULL; +} + +int doGetDeviceLocation(UsbdDevice_t *dev, u8 *path) +{ + const UsbdDevice_t *deviceTreeRoot; + int count; + int cpCount; + u8 tmpPath[16]; + + deviceTreeRoot = getDeviceTreeRoot(); + for ( count = 0; count < 6 && dev != deviceTreeRoot; count += 1, dev = dev->m_parent ) + { + tmpPath[count] = dev->m_attachedToPortNo; + } + if ( dev != deviceTreeRoot ) + return USB_RC_BADHUBDEPTH; + if ( count >= 6 ) + return USB_RC_BADHUBDEPTH; + for ( cpCount = 0; cpCount < 7; cpCount += 1 ) + { + path[cpCount] = (cpCount < count) ? tmpPath[count - cpCount - 1] : 0; + } + return USB_RC_OK; +} + +UsbdEndpoint_t *doOpenEndpoint(UsbdDevice_t *dev, const UsbEndpointDescriptor *endpDesc, u32 alignFlag) +{ + if ( !dev->m_parent ) + { + return NULL; + } + if ( !endpDesc ) + return dev->m_endpointListStart; // default control EP was already opened + return openDeviceEndpoint(dev, endpDesc, alignFlag); +} + +int doCloseEndpoint(UsbdEndpoint_t *ep) +{ + if ( ep->m_correspDevice->m_endpointListStart == ep ) + return 0; + return removeEndpointFromDevice(ep->m_correspDevice, ep); +} + +int attachIoReqToEndpoint(UsbdEndpoint_t *ep, UsbdIoRequest_t *req, void *destdata, u16 length, void *callback) +{ + if ( !ep->m_correspDevice ) + { + return USB_RC_BUSY; + } + if ( req->m_busyFlag ) + { + return USB_RC_BUSY; + } + req->m_busyFlag = 1; + req->m_correspEndpoint = ep; + req->m_destPtr = destdata; + req->m_length = length; + req->m_resultCode = USB_RC_OK; + req->m_callbackProc = (InternCallback)callback; + req->m_prev = ep->m_ioReqListEnd; + if ( ep->m_ioReqListEnd ) + ep->m_ioReqListEnd->m_next = req; + else + ep->m_ioReqListStart = req; + req->m_next = NULL; + ep->m_ioReqListEnd = req; + handleIoReqList(ep); + return USB_RC_OK; +} + +int doControlTransfer( + UsbdEndpoint_t *ep, + UsbdIoRequest_t *req, + u8 requestType, + u8 request, + u16 value, + u16 index, + u16 length, + void *destdata, + void *callback) +{ + if ( req->m_busyFlag ) + { + dbg_printf("ERROR: doControlTransfer: IoReq busy\n"); + return USB_RC_BUSY; + } + req->m_devReq.requesttype = requestType; + req->m_devReq.request = request; + req->m_devReq.value = value; + req->m_devReq.index = index; + req->m_devReq.length = length; + return attachIoReqToEndpoint(ep, req, destdata, length, callback); +} + +static void connectNewDevice(UsbdDevice_t *dev) +{ + sceUsbdLddOps *drv; + + dbg_printf("searching driver for dev %d, FA %02X\n", dev->m_id, dev->m_functionAddress); + dev->m_deviceStatus = DEVICE_READY; + for ( drv = drvListStart; drv; drv = drv->next ) + { + dev->m_privDataField = NULL; + if ( callUsbDriverFunc(drv->probe, dev->m_id, drv->gp) ) + { + dev->m_devDriver = drv; + dbg_printf("Driver found (%s)\n", drv->name); + callUsbDriverFunc(drv->connect, dev->m_id, drv->gp); + return; + } + } + // No driver found yet. Call autoloader. + drv = drvAutoLoader; + if ( drv ) + { + dev->m_privDataField = NULL; + if ( callUsbDriverFunc(drv->probe, dev->m_id, drv->gp) ) + { + dev->m_devDriver = drv; + dbg_printf("(autoloader) Driver found (%s)\n", drv->name); + callUsbDriverFunc(drv->connect, dev->m_id, drv->gp); + return; + } + } + dbg_printf("no driver found\n"); +} + +static void fetchNextReportDescriptorCB(UsbdIoRequest_t *req) +{ + req->m_correspEndpoint->m_correspDevice->m_reportDescriptorCurForFetch = + req->m_correspEndpoint->m_correspDevice->m_reportDescriptorCurForFetch->m_next; + if ( req->m_correspEndpoint->m_correspDevice->m_reportDescriptorCurForFetch ) + fetchNextReportDescriptor(req); + else + connectNewDevice(req->m_correspEndpoint->m_correspDevice); +} + +static void fetchNextReportDescriptor(UsbdIoRequest_t *req) +{ + doControlTransfer( + req->m_correspEndpoint, + &req->m_correspEndpoint->m_correspDevice->m_ioRequest, + USB_DIR_IN | USB_RECIP_INTERFACE, + 6u, + 0x2200u, + req->m_correspEndpoint->m_correspDevice->m_reportDescriptorCurForFetch->m_ifNum, + req->m_correspEndpoint->m_correspDevice->m_reportDescriptorCurForFetch->m_length, + req->m_correspEndpoint->m_correspDevice->m_reportDescriptorCurForFetch->m_data, + fetchNextReportDescriptorCB); +} + +static void killDevice(UsbdDevice_t *dev, UsbdEndpoint_t *ep) +{ + removeEndpointFromDevice(dev, ep); + checkDelayedResets(dev); + hubResetDevice(dev); +} + +static void fetchConfigDescriptors(UsbdIoRequest_t *req) +{ + UsbdDevice_t *dev; + const UsbDeviceDescriptor *staticDeviceDescPtr; + int fetchDescriptorCounter; + u32 fetchDesc_1; + int fetchDesc_2; + int curDescNum_1; + UsbConfigDescriptor *destdata; + int readLen; + + dev = req->m_correspEndpoint->m_correspDevice; + staticDeviceDescPtr = (UsbDeviceDescriptor *)dev->m_staticDeviceDescPtr; + if ( (int)dev->m_fetchDescriptorCounter > 0 && req->m_resultCode != USB_RC_OK ) + { + killDevice(req->m_correspEndpoint->m_correspDevice, req->m_correspEndpoint); + return; + } + fetchDescriptorCounter = dev->m_fetchDescriptorCounter; + fetchDesc_1 = fetchDescriptorCounter + 1; + dev->m_fetchDescriptorCounter = fetchDesc_1; + fetchDesc_2 = fetchDescriptorCounter & 1; + curDescNum_1 = fetchDescriptorCounter >> 1; + destdata = (UsbConfigDescriptor *)dev->m_staticDeviceDescEndPtr; + if ( curDescNum_1 > 0 && !fetchDesc_2 ) + dev->m_staticDeviceDescEndPtr = (u8 *)dev->m_staticDeviceDescEndPtr + READ_UINT16(&destdata->wTotalLength); + readLen = fetchDesc_2 ? READ_UINT16(&destdata->wTotalLength) : 4; + if ( (u8 *)dev->m_staticDeviceDescPtr + usbConfig.m_maxStaticDescSize < (u8 *)(&destdata->bLength + readLen) ) + { + dbg_printf("USBD: UsbdDevice_t ignored, UsbdDevice_t descriptors too large\n"); + return; // buffer is too small, silently ignore the device + } + if ( curDescNum_1 < staticDeviceDescPtr->bNumConfigurations ) + { + doControlTransfer( + req->m_correspEndpoint, + &dev->m_ioRequest, + USB_DIR_IN | USB_RECIP_DEVICE, + USB_REQ_GET_DESCRIPTOR, + curDescNum_1 | (USB_DT_CONFIG << 8), + 0, + readLen, + destdata, + fetchConfigDescriptors); + return; + } + dev->m_reportDescriptorStart = NULL; + if ( usbConfig.m_curDescNum ) + { + handleStaticDeviceDescriptor( + dev, (UsbDeviceDescriptor *)dev->m_staticDeviceDescPtr, (UsbDeviceDescriptor *)dev->m_staticDeviceDescEndPtr); + if ( dev->m_reportDescriptorStart ) + { + dev->m_reportDescriptorCurForFetch = dev->m_reportDescriptorStart; + fetchNextReportDescriptor(req); + return; + } + } + connectNewDevice(dev); +} + +static void requestDeviceDescrptorCB(UsbdIoRequest_t *req) +{ + UsbdDevice_t *dev; + const UsbDeviceDescriptor *desc; + + dev = req->m_correspEndpoint->m_correspDevice; + if ( req->m_resultCode != USB_RC_OK ) + { + dbg_printf("unable to read device descriptor, err %d\n", req->m_resultCode); + killDevice(req->m_correspEndpoint->m_correspDevice, req->m_correspEndpoint); + return; + } + if ( req->m_transferedBytes >= sizeof(UsbDeviceDescriptor) ) + { + dev->m_fetchDescriptorCounter = 0; + dev->m_staticDeviceDescEndPtr = &((UsbDeviceDescriptor *)dev->m_staticDeviceDescEndPtr)[1]; + fetchConfigDescriptors(req); + return; + } + desc = dev->m_staticDeviceDescPtr; + req->m_correspEndpoint->m_hcEd->m_hcArea.stru.m_maxPacketSize = + (req->m_correspEndpoint->m_hcEd->m_hcArea.stru.m_maxPacketSize & 0xF800) | desc->bMaxPacketSize0; + req->m_length = sizeof(UsbDeviceDescriptor); + requestDeviceDescriptor(req); +} + +static void requestDeviceDescriptor(UsbdIoRequest_t *req) +{ + UsbdDevice_t *dev; + + dev = req->m_correspEndpoint->m_correspDevice; + dev->m_staticDeviceDescEndPtr = dev->m_staticDeviceDescPtr; + doControlTransfer( + req->m_correspEndpoint, + &dev->m_ioRequest, + USB_DIR_IN | USB_RECIP_DEVICE, + USB_REQ_GET_DESCRIPTOR, + USB_DT_DEVICE << 8, + 0, + req->m_length, + dev->m_staticDeviceDescPtr, + requestDeviceDescrptorCB); +} + +static void hubPeekDeviceDescriptor(UsbdIoRequest_t *req) +{ + req->m_length = 8; + requestDeviceDescriptor(req); + + // we've assigned a function address to the device and can reset the next device now, if there is one + checkDelayedResets(req->m_correspEndpoint->m_correspDevice); +} + +static void hubSetFuncAddressCB(UsbdIoRequest_t *req) +{ + void *cb_arg; + UsbdDevice_t *dev; + void (*cb_func)(void *); + int cb_delay; + + dev = req->m_correspEndpoint->m_correspDevice; + if ( req->m_resultCode == USB_RC_NORESPONSE ) + { + dbg_printf("device not responding\n"); + dev->m_functionDelay <<= 1; + if ( dev->m_functionDelay > 0x500 ) + { + killDevice(dev, req->m_correspEndpoint); + return; + } + cb_func = (void (*)(void *))hubSetFuncAddress; + cb_arg = req->m_correspEndpoint; + cb_delay = dev->m_functionDelay | 1; + } + else + { + cb_func = (void (*)(void *))hubPeekDeviceDescriptor; + cb_arg = req; + cb_delay = 5; + req->m_correspEndpoint->m_hcEd->m_hcArea.stru.m_hcArea |= dev->m_functionAddress & 0x7F; + dev->m_deviceStatus = DEVICE_FETCHINGDESCRIPTOR; + } + addTimerCallback(&dev->m_timer, cb_func, cb_arg, cb_delay); +} + +static void hubSetFuncAddress(UsbdEndpoint_t *ep) +{ + // dbg_printf("setting FA %02X\n", ep->m_correspDevice->m_functionAddress); + doControlTransfer( + ep, + &ep->m_correspDevice->m_ioRequest, + USB_DIR_OUT | USB_RECIP_DEVICE, + USB_REQ_SET_ADDRESS, + ep->m_correspDevice->m_functionAddress, + 0, + 0, + NULL, + hubSetFuncAddressCB); +} + +int hubTimedSetFuncAddress(UsbdDevice_t *dev) +{ + dev->m_functionDelay = 20; + addTimerCallback(&dev->m_timer, (TimerCallback)hubSetFuncAddress, dev->m_endpointListStart, 21); + return 0; +} + +void flushPort(UsbdDevice_t *dev) +{ + UsbdReportDescriptor_t *desc; + UsbdDevice_t *child; + int state; + + if ( dev->m_deviceStatus != DEVICE_NOTCONNECTED ) + { + dev->m_deviceStatus = DEVICE_NOTCONNECTED; + if ( dev->m_devDriver ) + callUsbDriverFunc(dev->m_devDriver->disconnect, dev->m_id, dev->m_devDriver->gp); + dev->m_devDriver = NULL; + if ( dev->m_timer.m_isActive ) + cancelTimerCallback(&dev->m_timer); + while ( dev->m_endpointListStart ) + { + removeEndpointFromDevice(dev, dev->m_endpointListStart); + } + for ( desc = dev->m_reportDescriptorStart; desc; desc = dev->m_reportDescriptorStart ) + { + if ( desc->m_next ) + desc->m_next->m_prev = desc->m_prev; + else + dev->m_reportDescriptorEnd = desc->m_prev; + if ( desc->m_prev ) + desc->m_prev->m_next = desc->m_next; + else + dev->m_reportDescriptorStart = desc->m_next; + CpuSuspendIntr(&state); + FreeSysMemory(desc); + CpuResumeIntr(state); + } + while ( dev->m_childListStart ) + { + child = dev->m_childListStart; + if ( child->m_next ) + child->m_next->m_prev = child->m_prev; + else + dev->m_childListEnd = child->m_prev; + if ( child->m_prev ) + child->m_prev->m_next = child->m_next; + else + dev->m_childListStart = child->m_next; + flushPort(child); + freeDevice(child); + } + dev->m_ioRequest.m_busyFlag = 0; + } + if ( dev->m_resetFlag ) + checkDelayedResets(dev); +} + +int usbdInitInner(void) +{ + printf("USB Driver (%s)", usbdVersionString); + printf("\n"); + dbg_printf("HCD init...\n"); + if ( initHcdStructs() < 0 ) + return -1; + dbg_printf("Hub driver...\n"); + if ( initHubDriver() < 0 ) + return -1; + return 0; +} diff --git a/iop/usb/usbd/src/device_driver.c b/iop/usb/usbd/src/device_driver.c new file mode 100644 index 00000000000..e3c900b4906 --- /dev/null +++ b/iop/usb/usbd/src/device_driver.c @@ -0,0 +1,152 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +int callUsbDriverFunc(int (*func)(int devId), int devId, void *gpSeg) +{ + int res; + + if ( !func ) + return 0; + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(gpSeg); +#endif + res = func(devId); +#if USE_GP_REGISTER + SetGP(_gp); +#endif + usbdLock(); + return res; +} + +static void probeDeviceTree(UsbdDevice_t *tree, sceUsbdLddOps *drv) +{ + UsbdDevice_t *curDevice; + + for ( curDevice = tree->m_childListStart; curDevice; curDevice = curDevice->m_next ) + { + if ( curDevice->m_deviceStatus == DEVICE_READY ) + { + if ( curDevice->m_devDriver ) + { + if ( curDevice->m_childListStart ) + probeDeviceTree(curDevice, drv); + } + else + { + curDevice->m_privDataField = NULL; + if ( callUsbDriverFunc(drv->probe, curDevice->m_id, drv->gp) ) + { + curDevice->m_devDriver = drv; + callUsbDriverFunc(drv->connect, curDevice->m_id, drv->gp); + } + } + } + } +} + +int doRegisterDriver(sceUsbdLddOps *drv, void *drvGpSeg) +{ + if ( drv->next || drv->prev || !drv->name || drv->reserved1 || drv->reserved2 ) + { + return USB_RC_BADDRIVER; + } + if ( drvListStart == drv ) + { + return USB_RC_BUSY; + } + drv->gp = drvGpSeg; + drv->prev = drvListEnd; + if ( drvListEnd ) + drvListEnd->next = drv; + else + drvListStart = drv; + drv->next = NULL; + drvListEnd = drv; + if ( drv->probe ) + { + probeDeviceTree(getDeviceTreeRoot(), drv); + } + return USB_RC_OK; +} + +int doRegisterAutoLoader(sceUsbdLddOps *drv, void *drvGpSeg) +{ + if ( drv->next || drv->prev || !drv->name || drv->reserved1 || drv->reserved2 ) + { + return USB_RC_BADDRIVER; + } + if ( drvAutoLoader ) + { + return USB_RC_BUSY; + } + drv->gp = drvGpSeg; + drvAutoLoader = drv; + if ( drv->probe ) + { + probeDeviceTree(getDeviceTreeRoot(), drv); + } + return USB_RC_OK; +} + +static void disconnectDriver(UsbdDevice_t *tree, sceUsbdLddOps *drv) +{ + UsbdEndpoint_t *ep; + UsbdEndpoint_t *nextEp; + UsbdDevice_t *tree_tmp1; + + if ( drv == tree->m_devDriver ) + { + if ( tree->m_endpointListStart ) + { + ep = tree->m_endpointListStart->m_next; + for ( nextEp = ep; nextEp; ep = nextEp ) + { + nextEp = ep->m_next; + removeEndpointFromDevice(tree, ep); + } + } + tree->m_devDriver = NULL; + tree->m_privDataField = NULL; + } + for ( tree_tmp1 = tree->m_childListStart; tree_tmp1; tree_tmp1 = tree_tmp1->m_next ) + { + disconnectDriver(tree_tmp1, drv); + } +} + +int doUnregisterDriver(sceUsbdLddOps *drv) +{ + sceUsbdLddOps *pos; + + for ( pos = drvListStart; pos && pos != drv; pos = pos->next ) + { + } + if ( !pos ) + return USB_RC_BADDRIVER; + 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(getDeviceTreeRoot(), drv); + return USB_RC_OK; +} + +int doUnregisterAutoLoader(void) +{ + drvAutoLoader = NULL; + return USB_RC_OK; +} diff --git a/iop/usb/usbd/src/driver.c b/iop/usb/usbd/src/driver.c deleted file mode 100644 index 86230293dfd..00000000000 --- a/iop/usb/usbd/src/driver.c +++ /dev/null @@ -1,283 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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; -} diff --git a/iop/usb/usbd/src/driver.h b/iop/usb/usbd/src/driver.h deleted file mode 100644 index 4cf5d736d0b..00000000000 --- a/iop/usb/usbd/src/driver.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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__ diff --git a/iop/usb/usbd/src/endpoint.c b/iop/usb/usbd/src/endpoint.c new file mode 100644 index 00000000000..f2a3d03edb2 --- /dev/null +++ b/iop/usb/usbd/src/endpoint.c @@ -0,0 +1,326 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +static void addToHcEndpointList(u8 type, UsbdHcED_t *ed) +{ + ed->m_next = memPool->m_hcEdBuf[type].m_next; + memPool->m_hcEdBuf[type].m_next = ed; +} + +static void removeHcEdFromList(int type, const UsbdHcED_t *hcEd) +{ + UsbdHcED_t *prev; + UsbdHcED_t *pos; + + prev = &memPool->m_hcEdBuf[type]; + for ( pos = prev->m_next; pos && pos != hcEd; prev = pos, pos = pos->m_next ) + { + } + if ( pos ) + { + prev->m_next = pos->m_next; + } +} + +static int +setupBandwidthInterruptScheduling(UsbdEndpoint_t *ep, const UsbEndpointDescriptor *endpDesc, int isLowSpeedDevice) +{ + int maxPacketSize; + u32 *interruptBandwidthSchedulingValues; + int endpType; + int waitHigh; + int waitLow; + int schedulingIndex; + int i; + int packetSizeForScheduling; + u32 *value_ptr2; + + maxPacketSize = endpDesc->wMaxPacketSizeLB + (endpDesc->wMaxPacketSizeHB << 8); + interruptBandwidthSchedulingValues = memPool->m_interruptBandwidthSchedulingValues; + if ( endpDesc->bInterval >= 0x20u ) + { + endpType = 31; + waitHigh = 1; + waitLow = 32; + } + else if ( endpDesc->bInterval >= 0x10u ) + { + endpType = 15; + waitHigh = 2; + waitLow = 16; + } + else if ( endpDesc->bInterval >= 8u ) + { + endpType = 7; + waitHigh = 4; + waitLow = 8; + } + else if ( endpDesc->bInterval >= 4u ) + { + endpType = 3; + waitHigh = 8; + waitLow = 4; + } + else if ( endpDesc->bInterval >= 2u ) + { + endpType = 1; + waitHigh = 16; + waitLow = 2; + } + else + { + endpType = 0; + waitHigh = 32; + waitLow = 1; + } + schedulingIndex = 0; + if ( waitLow >= 2 ) + { + int maxValueSum; + + schedulingIndex = -1; + maxValueSum = 0; + for ( i = 0; i < waitLow; i += 1 ) + { + int valueSum; + u32 *value_ptr1; + int j; + + valueSum = 0; + value_ptr1 = &interruptBandwidthSchedulingValues[i]; + for ( j = 0; j < waitHigh; j += 1 ) + { + valueSum += *value_ptr1; + value_ptr1 += waitLow; + } + if ( schedulingIndex < 0 || valueSum < maxValueSum ) + { + schedulingIndex = i; + maxValueSum = valueSum; + } + } + endpType += schedulingIndex; + } + packetSizeForScheduling = maxPacketSize + 13; + if ( maxPacketSize >= 65 ) + packetSizeForScheduling = 77; + ep->m_schedulingIndex = schedulingIndex; + ep->m_waitHigh = waitHigh; + ep->m_waitLow = waitLow; + ep->m_packetSizeForScheduling = packetSizeForScheduling; + if ( isLowSpeedDevice ) + packetSizeForScheduling *= 8; + value_ptr2 = &interruptBandwidthSchedulingValues[schedulingIndex]; + for ( i = 0; i < waitHigh; i += 1 ) + { + *value_ptr2 += packetSizeForScheduling; + value_ptr2 += waitLow; + } + return endpType; +} + +static void removeEndpointFromQueue(const UsbdEndpoint_t *ep, int isLowSpeedDevice) +{ + int i; + u32 *value_ptr; + + value_ptr = &memPool->m_interruptBandwidthSchedulingValues[ep->m_schedulingIndex]; + for ( i = 0; i < ep->m_waitHigh; i += 1 ) + { + *value_ptr -= (ep->m_packetSizeForScheduling * (isLowSpeedDevice ? 8 : 1)); + if ( (int)*value_ptr < 0 ) + *value_ptr = 0; + value_ptr += ep->m_waitLow; + } +} + +UsbdEndpoint_t *openDeviceEndpoint(UsbdDevice_t *dev, const UsbEndpointDescriptor *endpDesc, u32 alignFlag) +{ + UsbdHcTD_t *td; + int endpType; + UsbdEndpoint_t *newEp; + + td = NULL; + endpType = 0; + newEp = allocEndpointForDevice(dev, alignFlag); + if ( !newEp ) + { + dbg_printf("ran out of endpoints\n"); + return NULL; + } + if ( endpDesc ) + { + int hcMaxPktSize; + int flags; + + hcMaxPktSize = endpDesc->wMaxPacketSizeLB + (endpDesc->wMaxPacketSizeHB << 8); + switch ( endpDesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK ) + { + case USB_ENDPOINT_XFER_CONTROL: + { + endpType = TYPE_CONTROL; + break; + } + case USB_ENDPOINT_XFER_ISOC: + { + endpType = TYPE_ISOCHRON; + td = (UsbdHcTD_t *)allocIsoTd(); + if ( !td ) + { + cleanUpFunc(dev, newEp); + dbg_printf("Open ISOC EP: no TDs left\n"); + return NULL; + } + alignFlag = 1; + break; + } + case USB_ENDPOINT_XFER_BULK: + { + endpType = TYPE_BULK; + if ( (endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ) + alignFlag = 1; + break; + } + case USB_ENDPOINT_XFER_INT: + { + endpType = setupBandwidthInterruptScheduling(newEp, endpDesc, dev->m_isLowSpeedDevice); + dbg_printf( + "opening INT endpoint (%d - %p), interval %d, list %d\n", newEp->m_id, newEp, endpDesc->bInterval, endpType); + if ( (endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ) + alignFlag = 1; + break; + } + default: + break; + } + if ( !alignFlag && hcMaxPktSize > 62 ) + { + hcMaxPktSize = 62; + } + flags = (hcMaxPktSize << 16) & 0x7FF0000; + if ( endpType == TYPE_ISOCHRON ) + flags |= HCED_ISOC; + if ( dev->m_isLowSpeedDevice ) + flags |= HCED_SPEED; + flags |= ((endpDesc->bEndpointAddress & 0x1F) << 7) + | ((endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN ? HCED_DIR_IN : HCED_DIR_OUT); + newEp->m_hcEd->m_hcArea.asu32 = flags | (dev->m_functionAddress & 0x7F); + } + else + { + newEp->m_hcEd->m_hcArea.asu32 = 0x80000; + newEp->m_hcEd->m_hcArea.asu32 |= dev->m_isLowSpeedDevice ? HCED_SPEED : 0; + endpType = TYPE_CONTROL; + } + newEp->m_endpointType = endpType; + if ( !td ) + { + td = allocTd(); + } + if ( !td ) + { + dbg_printf("Ran out of TDs\n"); + cleanUpFunc(dev, newEp); + return NULL; + } + newEp->m_hcEd->m_tdHead = td; + newEp->m_hcEd->m_tdTail = td; + addToHcEndpointList(endpType & 0xFF, newEp->m_hcEd); + return newEp; +} + +static void killEndpoint(UsbdEndpoint_t *ep) +{ + UsbdHcED_t *hcEd; + int i; + UsbdIoRequest_t *req; + + hcEd = ep->m_hcEd; + if ( ep->m_endpointType == TYPE_ISOCHRON ) + { + for ( i = 0; i < usbConfig.m_maxIsoTransfDesc; i += 1 ) + { + if ( memPool->m_hcIsoTdToIoReqLUT[i] && memPool->m_hcIsoTdToIoReqLUT[i]->m_correspEndpoint == ep ) + { + freeIoRequest(memPool->m_hcIsoTdToIoReqLUT[i]); + memPool->m_hcIsoTdToIoReqLUT[i] = NULL; + freeIsoTd(&memPool->m_hcIsoTdBuf[i]); + } + } + freeIsoTd((UsbdHcIsoTD_t *)hcEd->m_tdTail); + hcEd->m_tdTail = NULL; + } + else + { + for ( i = 0; i < usbConfig.m_maxTransfDesc; i += 1 ) + { + if ( memPool->m_hcTdToIoReqLUT[i] && memPool->m_hcTdToIoReqLUT[i]->m_correspEndpoint == ep ) + { + freeIoRequest(memPool->m_hcTdToIoReqLUT[i]); + memPool->m_hcTdToIoReqLUT[i] = NULL; + freeTd(&memPool->m_hcTdBuf[i]); + } + } + freeTd(hcEd->m_tdTail); + hcEd->m_tdTail = NULL; + } + hcEd->m_tdHead = NULL; + for ( req = ep->m_ioReqListStart; req; req = ep->m_ioReqListStart ) + { + if ( req->m_next ) + req->m_next->m_prev = req->m_prev; + else + ep->m_ioReqListEnd = req->m_prev; + if ( req->m_prev ) + req->m_prev->m_next = req->m_next; + else + ep->m_ioReqListStart = req->m_next; + freeIoRequest(req); + } + removeEndpointFromQueue(ep, ep->m_correspDevice->m_isLowSpeedDevice); + if ( ep->m_inTdQueue != NOTIN_QUEUE ) + { + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + else + memPool->m_tdQueueStart = ep->m_busyNext; + ep->m_inTdQueue = NOTIN_QUEUE; + } + ep->m_prev = memPool->m_freeEpListEnd; + if ( memPool->m_freeEpListEnd ) + memPool->m_freeEpListEnd->m_next = ep; + else + memPool->m_freeEpListStart = ep; + ep->m_next = NULL; + memPool->m_freeEpListEnd = ep; +} + +int removeEndpointFromDevice(UsbdDevice_t *dev, UsbdEndpoint_t *ep) +{ + ep->m_hcEd->m_hcArea.stru.m_hcArea |= HCED_SKIP; + removeHcEdFromList(ep->m_endpointType, ep->m_hcEd); + if ( ep->m_next ) + ep->m_next->m_prev = ep->m_prev; + else + dev->m_endpointListEnd = ep->m_prev; + if ( ep->m_prev ) + ep->m_prev->m_next = ep->m_next; + else + dev->m_endpointListStart = ep->m_next; + ep->m_correspDevice = NULL; + addTimerCallback(&ep->m_timer, (TimerCallback)killEndpoint, ep, 200); + return 0; +} diff --git a/iop/usb/usbd/src/exports.tab b/iop/usb/usbd/src/exports.tab index 5e1a15711d3..450f279cd23 100644 --- a/iop/usb/usbd/src/exports.tab +++ b/iop/usb/usbd/src/exports.tab @@ -1,23 +1,24 @@ -/**/ -DECLARE_EXPORT_TABLE(usbd, 1, 1) - DECLARE_EXPORT(_start) - DECLARE_EXPORT(_retonly) - DECLARE_EXPORT(_retonly) - 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_TABLE(usbd, 1, 2) +DECLARE_EXPORT(_start) +DECLARE_EXPORT(_retonly) +DECLARE_EXPORT(usbdReboot) +DECLARE_EXPORT(_retonly) +DECLARE_EXPORT(sceUsbdRegisterLdd) +DECLARE_EXPORT(sceUsbdUnregisterLdd) +DECLARE_EXPORT(sceUsbdScanStaticDescriptor) +DECLARE_EXPORT(sceUsbdSetPrivateData) +DECLARE_EXPORT(sceUsbdGetPrivateData) +DECLARE_EXPORT(sceUsbdOpenPipe) +DECLARE_EXPORT(sceUsbdClosePipe) +DECLARE_EXPORT(sceUsbdTransferPipe) +DECLARE_EXPORT(sceUsbdOpenPipeAligned) +DECLARE_EXPORT(sceUsbdGetDeviceLocation) +DECLARE_EXPORT(sceUsbdRegisterAutoloader) +DECLARE_EXPORT(sceUsbdUnregisterAutoloader) +DECLARE_EXPORT(sceUsbdChangeThreadPriority) +DECLARE_EXPORT(sceUsbdGetReportDescriptor) +DECLARE_EXPORT(sceUsbdMultiIsochronousTransfer) END_EXPORT_TABLE void _retonly() {} diff --git a/iop/usb/usbd/src/hcd.c b/iop/usb/usbd/src/hcd.c index a312b987493..3bdcb20f572 100644 --- a/iop/usb/usbd/src/hcd.c +++ b/iop/usb/usbd/src/hcd.c @@ -3,542 +3,333 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright 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 "mem.h" -#include "usbio.h" -#include "hub.h" -#include "driver.h" - -#include "stdio.h" -#include "sysclib.h" -#include "sysmem.h" -#include "thbase.h" -#include "thevent.h" -#include "thsemap.h" -#include "intrman.h" - -int hcdIrqEvent; -int hcdTid; - -int cleanUpFunc(Device *dev, Endpoint *ep) -{ - if (!ep) - return 0; - - if ((ep < memPool.endpointBuf) || (ep >= memPool.endpointBuf + usbConfig.maxEndpoints)) - return 0; - - if (ep->inTdQueue) - removeEndpointFromQueue(ep); - - if (ep->next) - ep->next->prev = ep->prev; - else - dev->endpointListEnd = ep->prev; - - if (ep->prev) - ep->prev->next = ep->next; - else - dev->endpointListStart = ep->next; - - ep->correspDevice = NULL; - ep->next = NULL; - ep->prev = memPool.freeEpListEnd; - if (memPool.freeEpListEnd) - memPool.freeEpListEnd->next = ep; - else - memPool.freeEpListStart = ep; - memPool.freeEpListEnd = ep; - return 0; -} - -Endpoint *openDeviceEndpoint(Device *dev, UsbEndpointDescriptor *endpDesc, u32 alignFlag) -{ - - u16 flags = 0; - u16 hcMaxPktSize; - u8 endpType = 0; - u8 type; - HcTD *td = NULL; - - Endpoint *newEp = allocEndpointForDevice(dev, alignFlag); - - if (!newEp) { - dbg_printf("ran out of endpoints\n"); - return NULL; - } - - if (endpDesc) { - type = endpDesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - hcMaxPktSize = (endpDesc->wMaxPacketSizeHB << 8) | endpDesc->wMaxPacketSizeLB; - - if (type == USB_ENDPOINT_XFER_ISOC) { - endpType = TYPE_ISOCHRON; - td = (HcTD *)allocIsoTd(); - if (!td) { - cleanUpFunc(dev, newEp); - dbg_printf("Open ISOC EP: no TDs left\n"); - return NULL; - } - } else if (type == USB_ENDPOINT_XFER_CONTROL) { - endpType = TYPE_CONTROL; - if (!alignFlag) - if (hcMaxPktSize >= 0x3F) - hcMaxPktSize = 0x3E; - } else { // BULK or INT - if (type == USB_ENDPOINT_XFER_INT) { - if (endpDesc->bInterval >= 0x20) - endpType = 0x1F; - else if (endpDesc->bInterval >= 0x10) - endpType = 0xF; - else if (endpDesc->bInterval >= 8) - endpType = 7; - else if (endpDesc->bInterval >= 4) - endpType = 3; - else if (endpDesc->bInterval >= 2) - endpType = 1; - else - endpType = 0; - - // todo: add bandwidth scheduling - - dbg_printf("opening INT endpoint (%d - %p), interval %d, list %d\n", newEp->id, newEp, endpDesc->bInterval, endpType); - } else - endpType = TYPE_BULK; - - if (((endpDesc->bEndpointAddress & USB_DIR_IN) == 0) && !alignFlag) - if (hcMaxPktSize >= 0x3F) - hcMaxPktSize = 0x3E; - } - - hcMaxPktSize &= 0x7FF; - if (type == USB_ENDPOINT_XFER_ISOC) - flags |= HCED_ISOC; - if (dev->isLowSpeedDevice) - flags |= HCED_SPEED; - - flags |= (endpDesc->bEndpointAddress & 0xF) << 7; - - if (endpDesc->bEndpointAddress & USB_DIR_IN) - flags |= HCED_DIR_IN; - else - flags |= HCED_DIR_OUT; - - flags |= dev->functionAddress & 0x7F; - - newEp->hcEd.hcArea = flags; - newEp->hcEd.maxPacketSize = hcMaxPktSize; - } else { - newEp->hcEd.maxPacketSize = 8; - if (dev->isLowSpeedDevice) - newEp->hcEd.hcArea = HCED_SPEED; - else - newEp->hcEd.hcArea = 0; - endpType = TYPE_CONTROL; - } - newEp->endpointType = endpType; - if (!td) { - td = allocTd(); - if (!td) { - dbg_printf("Ran out of TDs\n"); - cleanUpFunc(dev, newEp); - return NULL; - } - } - newEp->hcEd.tdHead = newEp->hcEd.tdTail = td; - addToHcEndpointList(newEp->endpointType, &newEp->hcEd); - return newEp; -} - -Endpoint *doOpenEndpoint(Device *dev, UsbEndpointDescriptor *endpDesc, u32 alignFlag) -{ - if (!dev->parent) - return NULL; - - if (endpDesc == NULL) - return dev->endpointListStart; // default control EP was already opened - else - return openDeviceEndpoint(dev, endpDesc, alignFlag); -} - -int doCloseEndpoint(Endpoint *ep) -{ - Device *dev = ep->correspDevice; - - if (dev->endpointListStart != ep) - return removeEndpointFromDevice(dev, ep); - else - return 0; -} - -void *doGetDeviceStaticDescriptor(int devId, void *data, u8 type) -{ - UsbDeviceDescriptor *descBuf; - Device *dev = fetchDeviceById(devId); - if (!dev) - return NULL; - - if (data) - descBuf = (UsbDeviceDescriptor *)((u8 *)data + ((UsbDeviceDescriptor *)data)->bLength); - else - descBuf = (UsbDeviceDescriptor *)dev->staticDeviceDescPtr; - - if (type == 0) - return descBuf; - - while (((u8 *)descBuf < (u8 *)dev->staticDeviceDescEndPtr) && (descBuf->bLength >= 2)) { - if (descBuf->bDescriptorType == type) - return descBuf; - descBuf = (UsbDeviceDescriptor *)((u8 *)descBuf + descBuf->bLength); - } - return NULL; -} - -void handleRhsc(void) -{ - u32 portNum = 0; - Device *port = memPool.deviceTreeRoot->childListStart; - - while (port) { - u32 status = memPool.ohciRegs->HcRhPortStatus[portNum]; - memPool.ohciRegs->HcRhPortStatus[portNum] = C_PORT_FLAGS; // reset all flags - if (status & BIT(PORT_CONNECTION)) { - if ((port->deviceStatus != DEVICE_NOTCONNECTED) && (status & BIT(C_PORT_CONNECTION))) - flushPort(port); +#if 0 +static UsbdMemoryPool_t *memPool_unused = NULL; +#endif - if (port->deviceStatus == DEVICE_NOTCONNECTED) { - port->deviceStatus = DEVICE_CONNECTED; - addTimerCallback(&port->timer, (TimerCallback)hubResetDevice, port, 500); - } else if (port->deviceStatus == DEVICE_RESETPENDING) { - if (!(status & BIT(PORT_RESET))) { - port->deviceStatus = DEVICE_RESETCOMPLETE; - port->isLowSpeedDevice = (status >> PORT_LOW_SPEED) & 1; - Endpoint *ep = openDeviceEndpoint(port, NULL, 0); - if (ep) - hubTimedSetFuncAddress(port); - } - } - } else - flushPort(port); - port = port->next; - portNum++; - } -} +static void *hcdMemoryBuffer; void hcdProcessIntr(void) { - u32 intrFlags; - - intrFlags = memPool.ohciRegs->HcInterruptStatus & memPool.ohciRegs->HcInterruptEnable; - - if (intrFlags & OHCI_INT_SO) { - dbg_printf("HC: Scheduling overrun\n"); - memPool.ohciRegs->HcInterruptStatus = OHCI_INT_SO; - intrFlags &= ~OHCI_INT_SO; - } - - HcTD *doneQueue = (HcTD *)((u32)memPool.hcHCCA->DoneHead & ~0xF); - if (doneQueue) { - memPool.hcHCCA->DoneHead = NULL; - memPool.ohciRegs->HcInterruptStatus = OHCI_INT_WDH; - - // reverse queue - HcTD *prev = NULL; - do { - HcTD *tmp = doneQueue; - doneQueue = tmp->next; - tmp->next = prev; - prev = tmp; - } while (doneQueue); - - do { - HcTD *tmp = prev->next; - if ((prev >= memPool.hcTdBuf) && (prev < memPool.hcTdBufEnd)) - processDoneQueue_GenTd(prev); - else if ((prev >= (HcTD *)memPool.hcIsoTdBuf) && (prev < (HcTD *)memPool.hcIsoTdBufEnd)) - processDoneQueue_IsoTd((HcIsoTD *)prev); - prev = tmp; - } while (prev); - - intrFlags &= ~OHCI_INT_WDH; - } - - if (intrFlags & OHCI_INT_SF) { - memPool.ohciRegs->HcInterruptStatus = OHCI_INT_SF; - handleTimerList(); - intrFlags &= ~OHCI_INT_SF; - } - - if (intrFlags & OHCI_INT_UE) { - printf("HC: Unrecoverable error\n"); - memPool.ohciRegs->HcInterruptStatus = OHCI_INT_UE; - intrFlags &= ~OHCI_INT_UE; - } - - if (intrFlags & OHCI_INT_RHSC) { - dbg_printf("RHSC\n"); - memPool.ohciRegs->HcInterruptStatus = OHCI_INT_RHSC; - handleRhsc(); - intrFlags &= ~OHCI_INT_RHSC; - } - - intrFlags &= ~OHCI_INT_MIE; - if (intrFlags) { - dbg_printf("Disable intr: %d\n", intrFlags); - memPool.ohciRegs->HcInterruptDisable = intrFlags; - } -} - -static void PostIntrEnableFunction(void) -{ - memPool.ohciRegs->HcInterruptDisable = OHCI_INT_MIE; - asm volatile("lw $zero, 0xffffffffbfc00000\n"); - memPool.ohciRegs->HcInterruptEnable = OHCI_INT_MIE; -} - -void hcdIrqThread(void *arg) -{ - u32 eventRes; - - (void)arg; - - while (1) { - WaitEventFlag(hcdIrqEvent, 1, WEF_CLEAR | WEF_OR, &eventRes); - - usbdLock(); - hcdProcessIntr(); - EnableIntr(IOP_IRQ_USB); - PostIntrEnableFunction(); - usbdUnlock(); - } + volatile OhciRegs *ohciRegs; + volatile HcCA *hcHCCA; + int intrFlags; + UsbdHcTD_t *doneQueue; + UsbdHcTD_t *prev; + UsbdHcTD_t *next_tmp1; + UsbdHcTD_t *next_tmp2; + + ohciRegs = memPool->m_ohciRegs; + memPool->m_interruptCounters[0] += 1; + hcHCCA = memPool->m_hcHCCA; + intrFlags = ohciRegs->HcInterruptStatus & ohciRegs->HcInterruptEnable; + if ( (intrFlags & OHCI_INT_SO) != 0 ) + { + dbg_printf("HC: Scheduling overrun\n"); + ohciRegs->HcInterruptStatus = OHCI_INT_SO; + intrFlags &= ~OHCI_INT_SO; + memPool->m_interruptCounters[1] += 1; + } + doneQueue = (UsbdHcTD_t *)((uiptr)hcHCCA->DoneHead & ~0xF); + prev = NULL; + if ( doneQueue ) + { + hcHCCA->DoneHead = NULL; + ohciRegs->HcInterruptStatus = OHCI_INT_WDH; + + // reverse queue + while ( doneQueue ) + { + next_tmp1 = doneQueue; + doneQueue = doneQueue->m_next; + next_tmp1->m_next = prev; + prev = next_tmp1; + } + for ( ; prev; prev = next_tmp2 ) + { + next_tmp2 = prev->m_next; + if ( prev < memPool->m_hcTdBuf || prev >= memPool->m_hcTdBufEnd ) + { + if ( (UsbdHcIsoTD_t *)prev >= memPool->m_hcIsoTdBuf && (UsbdHcIsoTD_t *)prev < memPool->m_hcIsoTdBufEnd ) + processDoneQueue_IsoTd((UsbdHcIsoTD_t *)prev); + } + else + { + processDoneQueue_GenTd(prev); + } + } + intrFlags &= ~OHCI_INT_WDH; + memPool->m_interruptCounters[2] += 1; + } + if ( (intrFlags & OHCI_INT_SF) != 0 ) + { + ohciRegs->HcInterruptStatus = OHCI_INT_SF; + handleTimerList(); + intrFlags &= ~OHCI_INT_SF; + memPool->m_interruptCounters[3] += 1; + } + if ( (intrFlags & OHCI_INT_RD) != 0 ) + { + ohciRegs->HcInterruptStatus = OHCI_INT_RD; + intrFlags &= ~OHCI_INT_RD; + memPool->m_interruptCounters[4] += 1; + } + if ( (intrFlags & OHCI_INT_UE) != 0 ) + { + dbg_printf("HC: Unrecoverable error\n"); + ohciRegs->HcInterruptStatus = OHCI_INT_UE; + intrFlags &= ~OHCI_INT_UE; + memPool->m_interruptCounters[5] += 1; + } + if ( (intrFlags & OHCI_INT_FNO) != 0 ) + { + ohciRegs->HcInterruptStatus = OHCI_INT_FNO; + intrFlags &= ~OHCI_INT_FNO; + memPool->m_interruptCounters[6] += 1; + } + if ( (intrFlags & OHCI_INT_RHSC) != 0 ) + { + dbg_printf("RHSC\n"); + ohciRegs->HcInterruptStatus = OHCI_INT_RHSC; + handleRhsc(); + intrFlags &= ~OHCI_INT_RHSC; + memPool->m_interruptCounters[7] += 1; + } + if ( (intrFlags & OHCI_INT_OC) != 0 ) + { + ohciRegs->HcInterruptStatus = OHCI_INT_OC; + intrFlags &= ~OHCI_INT_OC; + memPool->m_interruptCounters[8] += 1; + } + intrFlags &= ~OHCI_INT_MIE; + if ( intrFlags ) + { + dbg_printf("Disable intr: %d\n", intrFlags); + ohciRegs->HcInterruptDisable = intrFlags; + } } -int usbdIntrHandler(void *arg) +void PostIntrEnableFunction(void) { - iSetEventFlag((int)arg, 1); - return 0; + volatile int lw_busy; + + lw_busy = 0; + memPool->m_ohciRegs->HcInterruptDisable = OHCI_INT_MIE; + do + { + u32 val; + val = *((volatile u32 *)0xBFC00000); + __asm__ __volatile__(" " : "=r"(val)); + lw_busy -= 1; + } while ( lw_busy > 0 ); + memPool->m_ohciRegs->HcInterruptEnable = OHCI_INT_MIE; } -int initHardware(void) +static int initHardware(volatile OhciRegs *ohciRegs) { - unsigned int i; - - dbg_printf("Host Controller...\n"); - memPool.ohciRegs->HcInterruptDisable = ~0; - memPool.ohciRegs->HcCommandStatus = OHCI_COM_HCR; - memPool.ohciRegs->HcControl = 0; - - for (i = 0; memPool.ohciRegs->HcCommandStatus & OHCI_COM_HCR; i++) { - if (i == 1000) - return -1; - - asm volatile("lw $zero, 0xffffffffbfc00000\n"); - } - dbg_printf("HC reset done\n"); - *(volatile u32 *)0xBF801570 |= 0x800 << 16; - *(volatile u32 *)0xBF801680 = 1; - - return 0; + int i; + + dbg_printf("Host Controller...\n"); + ohciRegs->HcInterruptDisable = ~0; + ohciRegs->HcControl &= ~0x3Cu; + DelayThread(2000); + ohciRegs->HcCommandStatus = OHCI_COM_HCR; + ohciRegs->HcControl = 0; + for ( i = 1; i < 1000; i += 1 ) + { + volatile int lw_busy; + + if ( (ohciRegs->HcCommandStatus & OHCI_COM_HCR) == 0 ) + { + dbg_printf("HC reset done\n"); + return 0; + } + + lw_busy = 0; + do + { + u32 val; + val = *((volatile u32 *)0xBFC00000); + __asm__ __volatile__(" " : "=r"(val)); + lw_busy -= 1; + } while ( lw_busy > 0 ); + } + return -1; } int initHcdStructs(void) { - int i; - HcCA *hcCommArea; - memPool.ohciRegs = (volatile OhciRegs *)OHCI_REG_BASE; - - initHardware(); - - dbg_printf("Structs...\n"); - - memPool.hcHCCA = NULL; - memPool.hcIsoTdBuf = (HcIsoTD *)(sizeof(HcCA)); - memPool.hcIsoTdBufEnd = memPool.hcIsoTdBuf + usbConfig.maxIsoTransfDesc; - memPool.hcTdBuf = (HcTD *)memPool.hcIsoTdBufEnd; - memPool.hcTdBufEnd = memPool.hcTdBuf + usbConfig.maxTransfDesc; - memPool.hcEdBuf = (HcED *)memPool.hcTdBufEnd; - memPool.endpointBuf = (Endpoint *)(memPool.hcEdBuf + 0x42); - memPool.deviceTreeBuf = (Device *)(memPool.endpointBuf + usbConfig.maxEndpoints); - memPool.ioReqBufPtr = (IoRequest *)(memPool.deviceTreeBuf + usbConfig.maxDevices); - memPool.hcIsoTdToIoReqLUT = (IoRequest **)(memPool.ioReqBufPtr + usbConfig.maxIoReqs); - memPool.hcTdToIoReqLUT = (IoRequest **)(memPool.hcIsoTdToIoReqLUT + usbConfig.maxIsoTransfDesc); - - u8 *devDescBuf = (u8 *)(memPool.hcTdToIoReqLUT + usbConfig.maxTransfDesc); - u32 memSize = ((u32)devDescBuf) + usbConfig.maxDevices * usbConfig.maxStaticDescSize; - - u8 *memBuf = AllocSysMemory(ALLOC_FIRST, memSize, 0); - memset(memBuf, 0, memSize); - - hcCommArea = (HcCA *)memBuf; - memPool.hcHCCA = (HcCA *)((((u32)memBuf + (u32)memPool.hcHCCA) & 0x1FFFFFFF) | 0xA0000000); - memPool.hcIsoTdBuf = (HcIsoTD *)((u32)memBuf + (u32)memPool.hcIsoTdBuf); - memPool.hcIsoTdBufEnd = (HcIsoTD *)((u32)memBuf + (u32)memPool.hcIsoTdBufEnd); - memPool.hcTdBuf = (HcTD *)((u32)memBuf + (u32)memPool.hcTdBuf); - memPool.hcTdBufEnd = (HcTD *)((u32)memBuf + (u32)memPool.hcTdBufEnd); - memPool.hcEdBuf = (HcED *)((u32)memBuf + (u32)memPool.hcEdBuf); - memPool.endpointBuf = (Endpoint *)((u32)memBuf + (u32)memPool.endpointBuf); - memPool.deviceTreeBuf = (Device *)((u32)memBuf + (u32)memPool.deviceTreeBuf); - memPool.ioReqBufPtr = (IoRequest *)((u32)memBuf + (u32)memPool.ioReqBufPtr); - memPool.hcIsoTdToIoReqLUT = (IoRequest **)((u32)memBuf + (u32)memPool.hcIsoTdToIoReqLUT); - memPool.hcTdToIoReqLUT = (IoRequest **)((u32)memBuf + (u32)memPool.hcTdToIoReqLUT); - - devDescBuf = (u8 *)((u32)memBuf + (u32)devDescBuf); - - Endpoint *ep = memPool.endpointBuf; - - for (i = 0; i < usbConfig.maxEndpoints; i++) { - ep->id = i; - - ep->next = NULL; - ep->prev = memPool.freeEpListEnd; - if (memPool.freeEpListEnd) - memPool.freeEpListEnd->next = ep; - else - memPool.freeEpListStart = ep; - memPool.freeEpListEnd = ep; - ep++; - } - - memPool.tdQueueStart[0] = memPool.tdQueueStart[1] = NULL; - memPool.tdQueueEnd[0] = memPool.tdQueueEnd[1] = NULL; - - Device *dev = memPool.deviceTreeBuf; - for (i = 0; i < usbConfig.maxDevices; i++) { - dev->functionAddress = i; - dev->id = i & 0xFF; - - dev->next = NULL; - dev->prev = memPool.freeDeviceListEnd; - if (memPool.freeDeviceListEnd) - memPool.freeDeviceListEnd->next = dev; - else - memPool.freeDeviceListStart = dev; - memPool.freeDeviceListEnd = dev; - - dev->staticDeviceDescPtr = devDescBuf; - dev++; - devDescBuf += usbConfig.maxStaticDescSize; - } - - memPool.deviceTreeRoot = attachChildDevice(NULL, 0); // virtual root - attachChildDevice(memPool.deviceTreeRoot, 1); // root hub port 0 - attachChildDevice(memPool.deviceTreeRoot, 2); // root hub port 1 - - IoRequest *req = memPool.ioReqBufPtr; - for (i = 0; i < usbConfig.maxIoReqs; i++) { - req->next = NULL; - req->prev = memPool.freeIoReqListEnd; - if (memPool.freeIoReqListEnd) - memPool.freeIoReqListEnd->next = req; - else - memPool.freeIoReqList = req; - memPool.freeIoReqListEnd = req; - req++; - } - - HcTD *hcTd = memPool.freeHcTdList = memPool.hcTdBuf; - for (i = 0; i < usbConfig.maxTransfDesc - 1; i++) { - hcTd->next = hcTd + 1; - hcTd++; - } - hcTd->next = NULL; - - HcIsoTD *isoTd = memPool.freeHcIsoTdList = memPool.hcIsoTdBuf; - for (i = 0; i < usbConfig.maxIsoTransfDesc - 1; i++) { - isoTd->next = isoTd + 1; - isoTd++; - } - isoTd->next = NULL; - - // build tree for interrupt table - HcED *ed = memPool.hcEdBuf; - for (i = 0; i < 0x3F; i++) { - ed->hcArea = HCED_SKIP; - if (i == 0) - ed->next = NULL; - else - ed->next = memPool.hcEdBuf + ((i - 1) >> 1); - - int intrId = i - 31; - if (intrId >= 0) { - intrId = ((intrId & 1) << 4) | ((intrId & 2) << 2) | (intrId & 4) | ((intrId & 8) >> 2) | ((intrId & 0x10) >> 4); - hcCommArea->InterruptTable[intrId] = ed; - } - ed++; - } - - ed->hcArea = HCED_SKIP; - memPool.ohciRegs->HcControlHeadEd = ed; - ed++; - - ed->hcArea = HCED_SKIP; - memPool.ohciRegs->HcBulkHeadEd = ed; - ed++; - - ed->hcArea = HCED_SKIP; - memPool.hcEdBuf->next = ed; // the isochronous endpoint - - memPool.ohciRegs->HcHCCA = hcCommArea; - memPool.ohciRegs->HcFmInterval = 0x27782EDF; - memPool.ohciRegs->HcPeriodicStart = 0x2A2F; - memPool.ohciRegs->HcInterruptEnable = OHCI_INT_MIE | OHCI_INT_RHSC | OHCI_INT_UE | OHCI_INT_WDH | OHCI_INT_SO; - memPool.ohciRegs->HcControl = OHCI_CTR_USB_OPERATIONAL | OHCI_CTR_PLE | OHCI_CTR_IE | OHCI_CTR_CLE | OHCI_CTR_BLE | 3; - return 0; + int memSize; + void *memBuf_1; + HcCA *hcCommArea; + UsbdHcIsoTD_t *hcIsoTdBuf; + UsbdHcTD_t *hcTdBuf; + int i; + UsbdHcED_t *hcEdBufForEndpoint; + UsbdHcED_t *hcEdBuf; + UsbdEndpoint_t *endpointBuf; + UsbdDevice_t *deviceTreeBuf; + UsbdIoRequest_t *ioReqBuf; + UsbdIoRequest_t **hcIsoTdToIoReqLUT; + UsbdIoRequest_t **hcTdToIoReqLUT; + UsbdIoRequest_t **devDescBuf; + volatile OhciRegs *ohciRegs; + + ohciRegs = (volatile OhciRegs *)OHCI_REG_BASE; + if ( initHardware(ohciRegs) < 0 ) + return -1; + *(vu32 *)0xBF801570 |= 0x8000000u; + *(vu32 *)0xBF801680 = 1; + dbg_printf("Structs...\n"); + memSize = 0 + 28 + sizeof(HcCA) + sizeof(UsbdHcIsoTD_t) * usbConfig.m_maxIsoTransfDesc + + sizeof(UsbdHcTD_t) * usbConfig.m_maxTransfDesc + sizeof(UsbdHcED_t) * usbConfig.m_maxEndpoints + + sizeof(UsbdHcED_t) * 66 + sizeof(UsbdEndpoint_t) * usbConfig.m_maxEndpoints + + sizeof(UsbdDevice_t) * usbConfig.m_maxDevices + sizeof(UsbdIoRequest_t) * usbConfig.m_maxIoReqs + + sizeof(UsbdIoRequest_t *) * usbConfig.m_maxIsoTransfDesc + + sizeof(UsbdIoRequest_t *) * usbConfig.m_maxTransfDesc + + usbConfig.m_maxStaticDescSize * usbConfig.m_maxDevices; + memBuf_1 = AllocSysMemoryWrap(memSize); + if ( !memBuf_1 ) + return -1; + if ( ((uiptr)memBuf_1) & 0xFF ) + { + FreeSysMemoryWrap(memBuf_1); + return -1; + } + hcdMemoryBuffer = memBuf_1; + hcCommArea = (HcCA *)memBuf_1; + bzero(memBuf_1, memSize); + hcIsoTdBuf = (UsbdHcIsoTD_t *)(((uiptr)memBuf_1 + (28 + sizeof(HcCA) - 1)) & 0xFFFFFFE0); +#if 0 + *(UsbdConfig_t **)((u8 *)hcIsoTdBuf - 28) = &usbConfig; +#endif + hcTdBuf = (UsbdHcTD_t *)&hcIsoTdBuf[usbConfig.m_maxIsoTransfDesc]; + hcEdBufForEndpoint = (UsbdHcED_t *)&hcTdBuf[usbConfig.m_maxTransfDesc]; + hcEdBuf = (UsbdHcED_t *)&hcEdBufForEndpoint[usbConfig.m_maxEndpoints]; + memPool = (UsbdMemoryPool_t *)&hcEdBuf[66]; +#if 0 + memPool_unused = memPool; +#endif + endpointBuf = (UsbdEndpoint_t *)&memPool[1]; + deviceTreeBuf = (UsbdDevice_t *)&endpointBuf[usbConfig.m_maxEndpoints]; + ioReqBuf = (UsbdIoRequest_t *)&deviceTreeBuf[usbConfig.m_maxDevices]; + hcIsoTdToIoReqLUT = (UsbdIoRequest_t **)&ioReqBuf[usbConfig.m_maxIoReqs]; + hcTdToIoReqLUT = &hcIsoTdToIoReqLUT[usbConfig.m_maxIsoTransfDesc]; + devDescBuf = &hcTdToIoReqLUT[usbConfig.m_maxTransfDesc]; + usbConfig.m_allocatedSize_unused += memSize; + memPool->m_ohciRegs = ohciRegs; + memPool->m_hcEdBuf = hcEdBuf; + memPool->m_hcIsoTdToIoReqLUT = hcIsoTdToIoReqLUT; + memPool->m_hcTdToIoReqLUT = hcTdToIoReqLUT; + memPool->m_endpointBuf = endpointBuf; + memPool->m_hcHCCA = (volatile HcCA *)(((uiptr)memBuf_1 & 0x1FFFFFFF) | 0xA0000000); + for ( i = 0; i < usbConfig.m_maxEndpoints; i += 1 ) + { + endpointBuf[i].m_id = i; + endpointBuf[i].m_hcEd = &hcEdBufForEndpoint[i]; + endpointBuf[i].m_prev = memPool->m_freeEpListEnd; + if ( memPool->m_freeEpListEnd ) + memPool->m_freeEpListEnd->m_next = &endpointBuf[i]; + else + memPool->m_freeEpListStart = &endpointBuf[i]; + endpointBuf[i].m_next = NULL; + memPool->m_freeEpListEnd = &endpointBuf[i]; + } + memPool->m_tdQueueEnd = NULL; + memPool->m_tdQueueStart = NULL; + memPool->m_deviceTreeBuf = deviceTreeBuf; + for ( i = 0; i < usbConfig.m_maxDevices; i += 1 ) + { + deviceTreeBuf[i].m_functionAddress = i; + deviceTreeBuf[i].m_id = (u8)i; + deviceTreeBuf[i].m_staticDeviceDescPtr = (u8 *)devDescBuf + (usbConfig.m_maxStaticDescSize * i); + deviceTreeBuf[i].m_prev = memPool->m_freeDeviceListEnd; + if ( memPool->m_freeDeviceListEnd ) + memPool->m_freeDeviceListEnd->m_next = &deviceTreeBuf[i]; + else + memPool->m_freeDeviceListStart = &deviceTreeBuf[i]; + deviceTreeBuf[i].m_next = NULL; + memPool->m_freeDeviceListEnd = &deviceTreeBuf[i]; + } + memPool->m_deviceTreeRoot = attachChildDevice(NULL, 0); // virtual root + memPool->m_deviceTreeRoot->m_magicPowerValue = 2; + attachChildDevice(memPool->m_deviceTreeRoot, 1u); // root hub port 0 + attachChildDevice(memPool->m_deviceTreeRoot, 2u); // root hub port 1 + memPool->m_ioReqBufPtr = ioReqBuf; + for ( i = 0; i < usbConfig.m_maxIoReqs; i += 1 ) + { + ioReqBuf[i].m_id = i; + ioReqBuf[i].m_prev = memPool->m_freeIoReqListEnd; + if ( memPool->m_freeIoReqListEnd ) + memPool->m_freeIoReqListEnd->m_next = &ioReqBuf[i]; + else + memPool->m_freeIoReqList = &ioReqBuf[i]; + ioReqBuf[i].m_next = NULL; + memPool->m_freeIoReqListEnd = &ioReqBuf[i]; + } + memPool->m_freeHcTdList = hcTdBuf; + memPool->m_hcTdBuf = hcTdBuf; + memPool->m_hcTdBufEnd = &hcTdBuf[usbConfig.m_maxTransfDesc]; + for ( i = 0; i < usbConfig.m_maxTransfDesc - 1; i += 1 ) + { + hcTdBuf[i].m_next = &hcTdBuf[i + 1]; + } + memPool->m_freeHcIsoTdList = hcIsoTdBuf; + memPool->m_hcIsoTdBuf = hcIsoTdBuf; + memPool->m_hcIsoTdBufEnd = &hcIsoTdBuf[usbConfig.m_maxIsoTransfDesc]; + for ( i = 0; i < usbConfig.m_maxIsoTransfDesc - 1; i += 1 ) + { + hcIsoTdBuf[i].m_next = &hcIsoTdBuf[i + 1]; + } + // build tree for interrupt table + for ( i = 0; i < 63; i += 1 ) + { + int intrId; + hcEdBuf[i].m_hcArea.asu32 = HCED_SKIP; + hcEdBuf[i].m_next = (i > 0) ? &hcEdBuf[(i - 1) >> 1] : NULL; + intrId = i - 31; + if ( intrId >= 0 ) + { + intrId = ((intrId & 1) << 4) + ((intrId & 2) << 2) + (intrId & 4) + ((intrId & 8) >> 2) + ((intrId & 0x10) >> 4); + hcCommArea->InterruptTable[intrId] = &hcEdBuf[i]; + } + } + hcEdBuf[TYPE_CONTROL].m_hcArea.asu32 = HCED_SKIP; + ohciRegs->HcControlHeadEd = &hcEdBuf[TYPE_CONTROL]; + hcEdBuf[TYPE_BULK].m_hcArea.asu32 = HCED_SKIP; + ohciRegs->HcBulkHeadEd = &hcEdBuf[TYPE_BULK]; + hcEdBuf[TYPE_ISOCHRON].m_hcArea.asu32 = HCED_SKIP; + hcEdBuf[0].m_next = &hcEdBuf[TYPE_ISOCHRON]; // the isochronous endpoint + ohciRegs->HcHCCA = hcCommArea; + ohciRegs->HcFmInterval = 0x27782EDF; + ohciRegs->HcPeriodicStart = 0x2A2F; + ohciRegs->HcInterruptEnable = OHCI_INT_SO | OHCI_INT_WDH | OHCI_INT_UE | OHCI_INT_FNO | OHCI_INT_RHSC | OHCI_INT_MIE; + ohciRegs->HcControl |= + OHCI_CTR_CBSR | OHCI_CTR_PLE | OHCI_CTR_IE | OHCI_CTR_CLE | OHCI_CTR_BLE | OHCI_CTR_USB_OPERATIONAL; + return 0; } -int hcdInit(void) +void deinitHcd(void) { - int irqRes; - iop_event_t event; - iop_thread_t thread; - - dbg_printf("Threads and events...\n"); - event.attr = event.option = event.bits = 0; - hcdIrqEvent = CreateEventFlag(&event); - - dbg_printf("Intr handler...\n"); - DisableIntr(IOP_IRQ_USB, &irqRes); - if (RegisterIntrHandler(IOP_IRQ_USB, 1, usbdIntrHandler, (void *)hcdIrqEvent) != 0) { - if (irqRes == IOP_IRQ_USB) - EnableIntr(IOP_IRQ_USB); - return 1; - } - - dbg_printf("HCD thread...\n"); - thread.attr = TH_C; - thread.option = 0; - thread.thread = hcdIrqThread; -#ifndef MINI_DRIVER - thread.stacksize = 0x4000; // 16KiB -#else - thread.stacksize = 0x0800; // 2KiB -#endif - thread.priority = usbConfig.hcdThreadPrio; - hcdTid = CreateThread(&thread); - StartThread(hcdTid, (void *)hcdIrqEvent); - - dbg_printf("Callback thread...\n"); - initCallbackThread(); - - dbg_printf("HCD init...\n"); - initHcdStructs(); - - dbg_printf("Hub driver...\n"); - initHubDriver(); - - dbg_printf("Enabling interrupts...\n"); - EnableIntr(IOP_IRQ_USB); - - return 0; + UsbdDevice_t *i; + UsbdReportDescriptor_t *hidDescriptorStart; + UsbdReportDescriptor_t *next; + + initHardware((OhciRegs *)OHCI_REG_BASE); + for ( i = memPool->m_freeDeviceListStart; i; i = i->m_next ) + { + for ( hidDescriptorStart = i->m_reportDescriptorStart, next = hidDescriptorStart; next; hidDescriptorStart = next ) + { + next = hidDescriptorStart->m_next; + FreeSysMemoryWrap(hidDescriptorStart); + } + } + FreeSysMemoryWrap(hcdMemoryBuffer); } diff --git a/iop/usb/usbd/src/hcd.h b/iop/usb/usbd/src/hcd.h deleted file mode 100644 index f91376bcc5b..00000000000 --- a/iop/usb/usbd/src/hcd.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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 __HCD_H__ -#define __HCD_H__ - -#include "usbdpriv.h" - -int callUsbDriverFunc(int (*func)(int), int devId, void *gp); -Endpoint *openDeviceEndpoint(Device *dev, UsbEndpointDescriptor *endpDesc, u32 alignFlag); -Endpoint *doOpenEndpoint(Device *dev, UsbEndpointDescriptor *endpDesc, u32 alignFlag); -void *doGetDeviceStaticDescriptor(int devId, void *data, u8 type); -int doCloseEndpoint(Endpoint *ep); -int hcdInit(void); - -#endif // __HCD_H__ diff --git a/iop/usb/usbd/src/hub.c b/iop/usb/usbd/src/hub.c index 654a59e6f30..a26f92b73a2 100644 --- a/iop/usb/usbd/src/hub.c +++ b/iop/usb/usbd/src/hub.c @@ -3,735 +3,579 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright 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 "hcd.h" -#include "mem.h" -#include "usbio.h" -#include "driver.h" - -#include "defs.h" -#include "stdio.h" -#include "sysclib.h" -#include "sysmem.h" - -static UsbHub *hubBufferList; - -int hubDrvProbe(int devId); -int hubDrvConnect(int devId); -int hubDrvDisconnect(int devId); - -sceUsbdLddOps HubDriver = { - NULL, NULL, // next, prev - "hub", - hubDrvProbe, - hubDrvConnect, - hubDrvDisconnect, - 0, 0, 0, 0, 0, // reserved fields - 0 // gp + +static void hubStatusChangeCallback(UsbdIoRequest_t *req); +static int hubDrvConnect(int devId); +static int hubDrvDisconnect(int devId); +static int hubDrvProbe(int devId); + +static UsbdUsbHub_t *hubBufferList = NULL; +static void *hubBufferListMemoryBuffer = NULL; +static int hubAllocatedCount = 0; +static sceUsbdLddOps usbHubDriver = { + NULL, + NULL, + "hub", + &hubDrvProbe, + &hubDrvConnect, + &hubDrvDisconnect, + 0u, + 0u, + 0u, + 0u, + 0u, + NULL, }; +static UsbdUsbHub_t *allocHubBuffer(void) +{ + UsbdUsbHub_t *res; + + if ( !hubBufferList ) + { + return NULL; + } + res = hubBufferList; + hubBufferList = hubBufferList->m_next; + res->m_desc.bDescriptorType = 0; + res->m_statusIoReq.m_busyFlag = 0; + res->m_controlIoReq.m_busyFlag = 0; + res->m_curAllocatedCount = hubAllocatedCount; + hubAllocatedCount += 1; + return res; +} + +static void freeHubBuffer(UsbdUsbHub_t *hub) +{ + hub->m_next = hubBufferList; + hubBufferList = hub; +} + +static UsbdDevice_t *fetchPortElemByNumber(UsbdDevice_t *hub, int port) +{ + UsbdDevice_t *res; + + for ( res = hub->m_childListStart; res && port > 0; port -= 1, res = res->m_next ) + { + } + return res; +} + +static void getHubStatusChange(UsbdUsbHub_t *dev) +{ + if ( dev->m_statusIoReq.m_busyFlag ) + { + dbg_printf("getHubStatusChange: StatusChangeEP IoReq is busy!\n"); + return; + } + attachIoReqToEndpoint( + dev->m_statusChangeEp, + &dev->m_statusIoReq, + dev->m_statusChangeInfo, + (int)(dev->m_numChildDevices + 7) >> 3, + hubStatusChangeCallback); +} + +static void hubControlTransfer( + UsbdUsbHub_t *hubDev, + u8 requestType, + u8 request, + u16 value, + u16 index, + u16 length, + void *destData, + void *callback, + const char *fromfunc) +{ + if ( hubDev->m_controlIoReq.m_busyFlag ) + { + dbg_printf("ERROR: hubControlTransfer %p: ioReq busy\n", hubDev); + printf("hub_control_transfer: busy - %s\n", fromfunc); + } + else + doControlTransfer( + hubDev->m_controlEp, &hubDev->m_controlIoReq, requestType, request, value, index, length, destData, callback); +} + +static void hubGetPortStatusCallback(UsbdIoRequest_t *req) +{ + UsbdUsbHub_t *dev; + int feature; + UsbdDevice_t *port; + + dev = (UsbdUsbHub_t *)req->m_userCallbackArg; + feature = -1; + if ( req->m_resultCode != USB_RC_OK ) + { + dbg_printf("HubGetPortStatusCallback res %d\n", req->m_resultCode); + return; + } + dbg_printf("port status change: %d: %08X\n", dev->m_portCounter, dev->m_portStatusChange); + if ( (dev->m_portStatusChange & BIT(C_PORT_CONNECTION)) != 0 ) + { + port = fetchPortElemByNumber(dev->m_controlEp->m_correspDevice, dev->m_portCounter); + if ( !port ) + { + hubStatusChangeCallback(&dev->m_statusIoReq); + return; + } + if ( port->m_deviceStatus >= (unsigned int)DEVICE_CONNECTED ) + { + flushPort(port); + } + feature = C_PORT_CONNECTION; + } + else if ( (dev->m_portStatusChange & BIT(C_PORT_ENABLE)) != 0 ) + { + feature = C_PORT_ENABLE; + } + else if ( (dev->m_portStatusChange & BIT(C_PORT_SUSPEND)) != 0 ) + { + feature = C_PORT_SUSPEND; + } + else if ( (dev->m_portStatusChange & BIT(C_PORT_OVER_CURRENT)) != 0 ) + { + feature = C_PORT_OVER_CURRENT; + } + else if ( (dev->m_portStatusChange & BIT(C_PORT_RESET)) != 0 ) + { + feature = C_PORT_RESET; + } + if ( feature >= 0 ) + { + dev->m_portStatusChange &= ~BIT(feature); + hubControlTransfer( + dev, + USB_DIR_OUT | USB_RT_PORT, + USB_REQ_CLEAR_FEATURE, + feature & 0xFFFF, + dev->m_portCounter & 0xFFFF, + 0, + NULL, + hubGetPortStatusCallback, + "clear_port_feature"); + return; + } + port = fetchPortElemByNumber(dev->m_controlEp->m_correspDevice, dev->m_portCounter); + if ( port ) + { + if ( (dev->m_portStatusChange & BIT(PORT_CONNECTION)) != 0 ) + { + dbg_printf("Hub Port CCS\n"); + if ( port->m_deviceStatus == DEVICE_NOTCONNECTED ) + { + dbg_printf("resetting dev\n"); + port->m_deviceStatus = DEVICE_CONNECTED; + addTimerCallback(&port->m_timer, (TimerCallback)hubResetDevice, port, 501); + return; + } + if ( port->m_deviceStatus == DEVICE_RESETPENDING && (dev->m_portStatusChange & BIT(PORT_ENABLE)) != 0 ) + { + dbg_printf("hub port reset done, opening control EP\n"); + port->m_deviceStatus = DEVICE_RESETCOMPLETE; + port->m_isLowSpeedDevice = (dev->m_portStatusChange & BIT(PORT_LOW_SPEED)) != 0; + if ( openDeviceEndpoint(port, NULL, 0) ) + hubTimedSetFuncAddress(port); + else + dbg_printf("Can't open default control ep.\n"); + dev->m_hubStatusCounter = 0; + } + } + else + { + dbg_printf("disconnected; flushing port\n"); + flushPort(port); + } + } + hubStatusChangeCallback(&dev->m_statusIoReq); +} + +static void hubDeviceResetCallback(UsbdIoRequest_t *arg) +{ + if ( arg->m_resultCode != USB_RC_OK ) + { + dbg_printf("port reset err: %d\n", arg->m_resultCode); + return; + } + getHubStatusChange((UsbdUsbHub_t *)arg->m_userCallbackArg); +} + +void hubResetDevicePort(UsbdDevice_t *dev) +{ + UsbdUsbHub_t *privDataField; + + privDataField = (UsbdUsbHub_t *)dev->m_parent->m_privDataField; + privDataField->m_hubStatusCounter = dev->m_attachedToPortNo; + hubControlTransfer( + privDataField, + USB_DIR_OUT | USB_RT_PORT, + USB_REQ_SET_FEATURE, + PORT_RESET, + dev->m_attachedToPortNo, + 0, + NULL, + hubDeviceResetCallback, + "hub_port_reset"); +} + +static void hubCalculateMagicPowerValue(UsbdUsbHub_t *hubDevice) +{ + UsbdDevice_t *dev; + + dev = hubDevice->m_dev; + if ( (int)dev->m_magicPowerValue ) + { + if ( (int)dev->m_magicPowerValue >= 0 && (int)dev->m_magicPowerValue < 6 && (int)dev->m_magicPowerValue >= 3 ) + { + if ( (hubDevice->m_hubStatus & 1) != 0 ) + dev->m_magicPowerValue = 4; + else + dev->m_magicPowerValue = 5; + } + } + else if ( hubDevice->m_isSelfPowered ) + { + if ( (int)hubDevice->m_maxPower <= 0 ) + dev->m_magicPowerValue = 2; + else + dev->m_magicPowerValue = 3; + } + else + { + dev->m_magicPowerValue = (int)hubDevice->m_maxPower > 0; + } +} + +static void hubGetHubStatusCallback(UsbdIoRequest_t *req) +{ + UsbdUsbHub_t *dev; + + dev = (UsbdUsbHub_t *)req->m_userCallbackArg; + if ( req->m_resultCode != USB_RC_OK ) + { + return; + } + if ( (dev->m_hubStatusChange & BIT(C_HUB_LOCAL_POWER)) != 0 ) + { + dev->m_hubStatusChange &= ~BIT(C_HUB_LOCAL_POWER); + hubControlTransfer( + dev, + USB_DIR_OUT | USB_RT_HUB, + USB_REQ_CLEAR_FEATURE, + C_HUB_LOCAL_POWER, + 0, + 0, + NULL, + hubGetHubStatusCallback, + "clear_hub_feature"); + hubCalculateMagicPowerValue(dev); + } + else if ( (dev->m_hubStatusChange & BIT(C_HUB_OVER_CURRENT)) != 0 ) + { + dev->m_hubStatusChange &= ~BIT(C_HUB_OVER_CURRENT); + hubControlTransfer( + dev, + USB_DIR_OUT | USB_RT_HUB, + USB_REQ_CLEAR_FEATURE, + C_HUB_OVER_CURRENT, + 0, + 0, + NULL, + hubGetHubStatusCallback, + "clear_hub_feature"); + } + else + { + hubStatusChangeCallback(&dev->m_statusIoReq); + } +} + +static void hubStatusChangeCallback(UsbdIoRequest_t *req) +{ + UsbdUsbHub_t *dev; + int port; + + dev = (UsbdUsbHub_t *)req->m_userCallbackArg; + if ( req->m_resultCode != USB_RC_OK ) + { + dbg_printf("hubStatusChangeCallback, iores %d\n", req->m_resultCode); + return; + } + if ( (dev->m_statusChangeInfo[0] & 1) != 0 ) + { + dev->m_statusChangeInfo[0] &= ~1; + hubControlTransfer( + dev, + USB_DIR_IN | USB_RT_HUB, + USB_REQ_GET_STATUS, + 0, + 0, + 4u, + &dev->m_hubStatus, + hubGetHubStatusCallback, + "scan_change_bitmap"); + return; + } + port = dev->m_hubStatusCounter; + if ( port <= 0 ) + { + port = 1; + if ( (int)dev->m_numChildDevices <= 0 ) + { + getHubStatusChange(dev); + return; + } + while ( (((int)dev->m_statusChangeInfo[port >> 3] >> (port & 7)) & 1) == 0 ) + { + port += 1; + if ( (int)dev->m_numChildDevices < port ) + { + getHubStatusChange(dev); + return; + } + } + } + else if ( (((int)dev->m_statusChangeInfo[port >> 3] >> (port & 7)) & 1) == 0 ) + { + getHubStatusChange(dev); + return; + } + dev->m_statusChangeInfo[port >> 3] &= ~BIT(port & 7); + dev->m_portCounter = port; + hubControlTransfer( + dev, + USB_DIR_IN | USB_RT_PORT, + USB_REQ_GET_STATUS, + 0, + dev->m_portCounter, + 4u, + &dev->m_portStatusChange, + hubGetPortStatusCallback, + "scan_change_bitmap"); +} + +static void hubSetPortPower(UsbdIoRequest_t *req) +{ + UsbdUsbHub_t *dev; + + dev = (UsbdUsbHub_t *)req->m_userCallbackArg; + // there is no result to check if this is the first call for this hub + if ( (int)dev->m_portCounter > 0 && req->m_resultCode != USB_RC_OK ) + { + return; + } + dev->m_portCounter += 1; + if ( ((int)dev->m_numChildDevices < (int)dev->m_portCounter) || usbConfig.m_maxPortsPerHub < (int)dev->m_portCounter ) + getHubStatusChange(dev); + else + hubControlTransfer( + dev, + USB_DIR_OUT | USB_RT_PORT, + USB_REQ_SET_FEATURE, + PORT_POWER, + dev->m_portCounter, + 0, + NULL, + hubSetPortPower, + "set_port_power"); +} + +static void hubSetupPorts(UsbdIoRequest_t *req) +{ + UsbdUsbHub_t *dev; + u32 i; + + dev = (UsbdUsbHub_t *)req->m_userCallbackArg; + if ( req->m_resultCode != USB_RC_OK ) + { + return; + } + hubCalculateMagicPowerValue(dev); + + dev->m_hubStatusCounter = 0; + dev->m_portCounter = 0; + dev->m_numChildDevices = dev->m_desc.bNbrPorts; + for ( i = 0; (int)i < (int)dev->m_numChildDevices && (int)i < usbConfig.m_maxPortsPerHub; i += 1 ) + { + if ( !attachChildDevice(dev->m_controlEp->m_correspDevice, i + 1) ) + { + dev->m_numChildDevices = i; + break; + } + } + if ( (int)dev->m_numChildDevices > 0 ) + hubSetPortPower(req); +} + +static void hubCheckPorts(UsbdIoRequest_t *req) +{ + UsbdUsbHub_t *dev; + + dev = (UsbdUsbHub_t *)req->m_userCallbackArg; + hubControlTransfer( + dev, USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_STATUS, 0, 0, 4u, &dev->m_hubStatus, hubSetupPorts, "get_hub_status"); +} + +static void hubCheckPortsCB(UsbdIoRequest_t *req) +{ + if ( req->m_resultCode != USB_RC_OK ) + return; + hubCheckPorts(req); +} + +static void hubCheckDeviceDesc(UsbdIoRequest_t *req) +{ + UsbdUsbHub_t *dev; + + dev = (UsbdUsbHub_t *)req->m_userCallbackArg; + if ( req->m_resultCode != USB_RC_OK ) + { + return; + } + if ( dev->m_desc.bDescriptorType == USB_DT_HUB ) + hubCheckPorts(req); // we've got the descriptor already + else + hubControlTransfer( + dev, + USB_DIR_IN | USB_RT_HUB, + USB_REQ_GET_DESCRIPTOR, + USB_DT_HUB << 8, + 0, + sizeof(UsbHubDescriptor), + &dev->m_desc, + hubCheckPortsCB, + "set_configuration_done"); +} + +static int hubDrvConnect(int devId) +{ + UsbdDevice_t *dev; + UsbConfigDescriptor *confDesc; + UsbInterfaceDescriptor *intfDesc; + UsbEndpointDescriptor *endpDesc; + UsbdUsbHub_t *hubDevice; + const UsbHubDescriptor *hubDesc; + + dev = fetchDeviceById(devId); + if ( !dev ) + return -1; + confDesc = (UsbConfigDescriptor *)doGetDeviceStaticDescriptor(devId, NULL, USB_DT_CONFIG); + if ( !confDesc || confDesc->bNumInterfaces != 1 ) + return -1; + intfDesc = (UsbInterfaceDescriptor *)doGetDeviceStaticDescriptor(devId, confDesc, USB_DT_INTERFACE); + if ( !intfDesc ) + { + return -1; + } + if ( intfDesc->bNumEndpoints != 1 ) + { + return -1; + } + endpDesc = (UsbEndpointDescriptor *)doGetDeviceStaticDescriptor(devId, intfDesc, USB_DT_ENDPOINT); + if ( !endpDesc ) + { + return -1; + } + if ( (endpDesc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ) + return -1; + if ( (endpDesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT ) + return -1; + hubDesc = (UsbHubDescriptor *)doGetDeviceStaticDescriptor(devId, endpDesc, USB_DT_HUB); + hubDevice = allocHubBuffer(); + if ( !hubDevice ) + return -1; + dev->m_privDataField = hubDevice; + hubDevice->m_dev = dev; + hubDevice->m_controlEp = dev->m_endpointListStart; + hubDevice->m_statusChangeEp = doOpenEndpoint(dev, endpDesc, 0); + if ( !hubDevice->m_statusChangeEp ) + { + freeHubBuffer(hubDevice); + return -1; + } + hubDevice->m_statusIoReq.m_userCallbackArg = hubDevice; + hubDevice->m_controlIoReq.m_userCallbackArg = hubDevice; + hubDevice->m_maxPower = confDesc->maxPower; + hubDevice->m_isSelfPowered = (confDesc->bmAttributes >> 6) & 1; + hubCalculateMagicPowerValue(hubDevice); + if ( hubDesc ) + { + bcopy( + hubDesc, + &hubDevice->m_desc, + (hubDesc->bLength < sizeof(UsbHubDescriptor)) ? hubDesc->bLength : sizeof(UsbHubDescriptor)); + } + hubControlTransfer( + hubDevice, + USB_DIR_OUT | USB_RECIP_DEVICE, + USB_REQ_SET_CONFIGURATION, + confDesc->bConfigurationValue, + 0, + 0, + NULL, + hubCheckDeviceDesc, + "hub_attach"); + return 0; +} + +static int hubDrvDisconnect(int devId) +{ + UsbdDevice_t *dev; + + dev = fetchDeviceById(devId); + if ( !dev ) + return -1; + freeHubBuffer((UsbdUsbHub_t *)dev->m_privDataField); + return 0; +} + +static int hubDrvProbe(int devId) +{ + const UsbDeviceDescriptor *devDesc; + + devDesc = (const UsbDeviceDescriptor *)doGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); + return devDesc && devDesc->bDeviceClass == USB_CLASS_HUB && devDesc->bNumConfigurations == 1; +} + int initHubDriver(void) { - int i; - UsbHub *hub; - u32 needMem = usbConfig.maxHubDevices * sizeof(UsbHub); - - hubBufferList = (UsbHub *)AllocSysMemory(ALLOC_FIRST, needMem, 0); - if (!hubBufferList) { - dbg_printf("ERROR: unable to alloc hub buffer\n"); - return -1; - } - memset(hubBufferList, 0, needMem); - - hub = hubBufferList; - for (i = 0; i < usbConfig.maxHubDevices - 1; i++) { - hub->next = hub + 1; - hub++; - } - hub->next = NULL; - + int needMem; + UsbdUsbHub_t *hub; + int i; + void *OldGP; + + needMem = usbConfig.m_maxHubDevices * sizeof(UsbdUsbHub_t); + hubBufferList = (UsbdUsbHub_t *)AllocSysMemoryWrap(needMem); + if ( !hubBufferList ) + { + dbg_printf("ERROR: unable to alloc hub buffer\n"); + return -1; + } + hub = hubBufferList; + hubBufferListMemoryBuffer = hub; + bzero(hubBufferList, needMem); + usbConfig.m_allocatedSize_unused += needMem; + for ( i = 0; i < usbConfig.m_maxHubDevices; i += 1 ) + { + hub[i].m_next = (i < usbConfig.m_maxHubDevices - 1) ? &hub[i + 1] : NULL; + } #if USE_GP_REGISTER - doRegisterDriver(&HubDriver, &_gp); + OldGP = GetGP(); #else - doRegisterDriver(&HubDriver, NULL); + OldGP = NULL; #endif - return 0; -} - -UsbHub *allocHubBuffer(void) -{ - UsbHub *res = hubBufferList; - if (res) { - hubBufferList = res->next; - res->desc.bDescriptorType = 0; - res->controlIoReq.busyFlag = 0; - res->statusIoReq.busyFlag = 0; - } - return res; -} - -void freeHubBuffer(UsbHub *hub) -{ - if (hub) { - hub->next = hubBufferList; - hubBufferList = hub; - } -} - -void HubControlTransfer(UsbHub *hubDev, u8 requestType, u8 request, u16 value, - u16 index, u16 length, void *destData, - void *callback) -{ - if (!hubDev->controlIoReq.busyFlag) { - doControlTransfer(hubDev->controlEp, &hubDev->controlIoReq, - requestType, request, value, index, length, destData, - callback); - } else - dbg_printf("ERROR: HubControlTransfer %p: ioReq busy\n", hubDev); -} - -void hubGetHubStatusCallback(IoRequest *req); -void hubGetPortStatusCallback(IoRequest *req); -void getHubStatusChange(UsbHub *dev); - -void hubStatusChangeCallback(IoRequest *req) -{ - UsbHub *dev = (UsbHub *)req->userCallbackArg; - - if (req->resultCode == USB_RC_OK) { - if (dev->statusChangeInfo[0] & 1) { - dev->statusChangeInfo[0] &= ~1; - HubControlTransfer(dev, - USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_STATUS, 0, 0, 4, &dev->hubStatus, - hubGetHubStatusCallback); - } else { - int port; - - if (dev->hubStatusCounter > 0) { - port = dev->hubStatusCounter; - if (dev->statusChangeInfo[port >> 3] & BIT(port & 7)) { - dev->statusChangeInfo[port >> 3] &= ~BIT(port & 7); - dev->portCounter = port; - HubControlTransfer(dev, - USB_DIR_IN | USB_RT_PORT, USB_REQ_GET_STATUS, 0, port, 4, &dev->portStatusChange, - hubGetPortStatusCallback); - return; - } - } else { - for (port = 1; (u32)port <= dev->numChildDevices; port++) { - if (dev->statusChangeInfo[port >> 3] & BIT(port & 7)) { - dev->statusChangeInfo[port >> 3] &= ~BIT(port & 7); - dev->portCounter = port; - HubControlTransfer(dev, - USB_DIR_IN | USB_RT_PORT, USB_REQ_GET_STATUS, 0, port, 4, &dev->portStatusChange, - hubGetPortStatusCallback); - return; - } - } - } - getHubStatusChange(dev); - } - } else - dbg_printf("hubStatusChangeCallback, iores %d\n", req->resultCode); -} - -void hubGetHubStatusCallback(IoRequest *req) -{ - UsbHub *dev = (UsbHub *)req->userCallbackArg; - if (req->resultCode == USB_RC_OK) { - if (dev->hubStatusChange & BIT(C_HUB_LOCAL_POWER)) { - dev->hubStatusChange &= ~BIT(C_HUB_LOCAL_POWER); - HubControlTransfer(dev, - USB_DIR_OUT | USB_RT_HUB, USB_REQ_CLEAR_FEATURE, C_HUB_LOCAL_POWER, 0, 0, NULL, - hubGetHubStatusCallback); - - } else if (dev->hubStatusChange & BIT(C_HUB_OVER_CURRENT)) { - dev->hubStatusChange &= ~BIT(C_HUB_OVER_CURRENT); - HubControlTransfer(dev, - USB_DIR_OUT | USB_RT_HUB, USB_REQ_CLEAR_FEATURE, C_HUB_OVER_CURRENT, 0, 0, NULL, - hubGetHubStatusCallback); - - } else - hubStatusChangeCallback(&dev->statusIoReq); - } -} - -int cancelTimerCallback(TimerCbStruct *arg) -{ - if (arg->isActive) { - if (arg->next) - arg->next->prev = arg->prev; - else - memPool.timerListEnd = arg->prev; - - if (arg->prev) - arg->prev->next = arg->next; - else - memPool.timerListStart = arg->next; - - arg->prev = arg->next = NULL; - arg->isActive = 0; - return 0; - } else - return -1; -} - -int addTimerCallback(TimerCbStruct *arg, TimerCallback func, void *cbArg, u32 delay) -{ - if (arg->isActive) - return -1; - - arg->isActive = 1; - arg->callbackProc = func; - arg->callbackArg = cbArg; - - TimerCbStruct *pos = memPool.timerListStart; - - while (pos && (delay > pos->delayCount)) { - delay -= pos->delayCount; - pos = pos->next; - } - if (pos) { - arg->prev = pos->prev; - if (pos->prev) - pos->prev->next = arg; - else - memPool.timerListStart = arg; - - arg->next = pos; - pos->prev = arg; - pos->delayCount -= delay; - } else { - arg->prev = memPool.timerListEnd; - if (memPool.timerListEnd) - memPool.timerListEnd->next = arg; - else - memPool.timerListStart = arg; - memPool.timerListEnd = arg; - arg->next = NULL; - } - arg->delayCount = delay; - memPool.ohciRegs->HcInterruptEnable = OHCI_INT_SF; - return 0; -} - -void killEndpoint(Endpoint *ep) -{ - int i = 0; - IoRequest *req; - HcED *hcEd = &ep->hcEd; - if (ep->endpointType == TYPE_ISOCHRON) { - for (i = 0; i < usbConfig.maxIsoTransfDesc; i++) { - req = memPool.hcIsoTdToIoReqLUT[i]; - if (req && (req->correspEndpoint == ep)) { - freeIoRequest(req); - memPool.hcIsoTdToIoReqLUT[i] = NULL; - freeIsoTd(memPool.hcIsoTdBuf + i); - } - } - freeIsoTd((HcIsoTD *)hcEd->tdTail); - } else { - for (i = 0; i < usbConfig.maxTransfDesc; i++) { - req = memPool.hcTdToIoReqLUT[i]; - if (req && (req->correspEndpoint == ep)) { - freeIoRequest(req); - memPool.hcTdToIoReqLUT[i] = NULL; - freeTd(memPool.hcTdBuf + i); - } - } - freeTd(hcEd->tdTail); - } - hcEd->tdTail = NULL; - hcEd->tdHead = NULL; - - while ((req = ep->ioReqListStart)) { - if (req->next) - req->next->prev = req->prev; - else - ep->ioReqListEnd = req->prev; - - if (req->prev) - req->prev->next = req->next; - else - ep->ioReqListStart = req->next; - - freeIoRequest(req); - } - removeEndpointFromQueue(ep); - - ep->next = NULL; - ep->prev = memPool.freeEpListEnd; - if (memPool.freeEpListEnd) - memPool.freeEpListEnd->next = ep; - else - memPool.freeEpListStart = ep; - memPool.freeEpListEnd = ep; -} - -int removeEndpointFromDevice(Device *dev, Endpoint *ep) -{ - ep->hcEd.hcArea |= HCED_SKIP; - removeHcEdFromList(ep->endpointType, &ep->hcEd); - - if (ep->next) - ep->next->prev = ep->prev; - else - dev->endpointListEnd = ep->prev; - - if (ep->prev) - ep->prev->next = ep->next; - else - dev->endpointListStart = ep->next; - - ep->correspDevice = NULL; - addTimerCallback(&ep->timer, (TimerCallback)killEndpoint, ep, 200); - return 0; -} - -void hubDeviceResetCallback(IoRequest *arg) -{ - if (arg->resultCode == USB_RC_OK) - getHubStatusChange((UsbHub *)arg->userCallbackArg); - else - dbg_printf("port reset err: %d\n", arg->resultCode); -} - -void hubResetDevice(void *devp) -{ - Device *dev = devp; - if (memPool.delayResets) { - dev->deviceStatus = DEVICE_RESETDELAYED; - } else { - memPool.delayResets = 1; - dev->deviceStatus = DEVICE_RESETPENDING; - dev->resetFlag = 1; - if (dev->parent == memPool.deviceTreeRoot) { // root hub port - memPool.ohciRegs->HcRhPortStatus[dev->attachedToPortNo - 1] = BIT(PORT_RESET); - } else { // normal hub port - UsbHub *hub; - - hub = (UsbHub *)dev->parent->privDataField; - hub->hubStatusCounter = dev->attachedToPortNo; - - HubControlTransfer(hub, - USB_DIR_OUT | USB_RT_PORT, USB_REQ_SET_FEATURE, PORT_RESET, dev->attachedToPortNo, 0, NULL, - hubDeviceResetCallback); - } - } -} - -int checkDelayedResetsTree(Device *tree) -{ - Device *dev; - for (dev = tree->childListStart; dev != NULL; dev = dev->next) { - if (dev->deviceStatus == DEVICE_RESETDELAYED) { - hubResetDevice(dev); - return 1; - } - if ((dev->deviceStatus == DEVICE_READY) && dev->childListStart) { - if (checkDelayedResetsTree(dev)) - return 1; - } - } - return 0; -} - -int checkDelayedResets(Device *dev) -{ - memPool.delayResets = 0; - dev->resetFlag = 0; - checkDelayedResetsTree(memPool.deviceTreeRoot); - return 0; -} - -void killDevice(Device *dev, Endpoint *ep) -{ - removeEndpointFromDevice(dev, ep); - checkDelayedResets(dev); - hubResetDevice(dev); -} - -void flushPort(Device *dev) -{ - Device *child; - if (dev->deviceStatus != DEVICE_NOTCONNECTED) { - dev->deviceStatus = DEVICE_NOTCONNECTED; - if (dev->devDriver) { - callUsbDriverFunc(dev->devDriver->disconnect, dev->id, dev->devDriver->gp); - dev->devDriver = NULL; - } - - if (dev->timer.isActive) - cancelTimerCallback(&dev->timer); - - while (dev->endpointListStart) - removeEndpointFromDevice(dev, dev->endpointListStart); - - while ((child = dev->childListStart)) { - if (child->next) - child->next->prev = child->prev; - else - dev->childListEnd = child->prev; - - if (child->prev) - child->prev->next = child->next; - else - dev->childListStart = child->next; - - flushPort(child); - - freeDevice(child); - } - dev->ioRequest.busyFlag = 0; - dev->privDataField = NULL; - } - if (dev->resetFlag) - checkDelayedResets(dev); -} - -void fetchConfigDescriptors(IoRequest *req) -{ - Endpoint *ep = req->correspEndpoint; - Device *dev = ep->correspDevice; - u16 readLen; - - if ((req->resultCode == USB_RC_OK) || (dev->fetchDescriptorCounter == 0)) { - int fetchDesc; - - u32 curDescNum = dev->fetchDescriptorCounter++; - - fetchDesc = curDescNum & 1; - curDescNum >>= 1; - - if ((curDescNum > 0) && !fetchDesc) { - UsbConfigDescriptor *desc = dev->staticDeviceDescEndPtr; - dev->staticDeviceDescEndPtr = (void *)((u8 *)(dev->staticDeviceDescEndPtr) + READ_UINT16(&desc->wTotalLength)); - } - - if (fetchDesc) { - UsbConfigDescriptor *desc = dev->staticDeviceDescEndPtr; - readLen = READ_UINT16(&desc->wTotalLength); - } else - readLen = 4; - - if ((u8 *)dev->staticDeviceDescEndPtr + readLen > (u8 *)dev->staticDeviceDescPtr + usbConfig.maxStaticDescSize) { - dbg_printf("USBD: Device ignored, Device descriptors too large\n"); - return; // buffer is too small, silently ignore the device - } - - if (curDescNum < ((UsbDeviceDescriptor *)dev->staticDeviceDescPtr)->bNumConfigurations) { - doControlTransfer(ep, &dev->ioRequest, - USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR, (USB_DT_CONFIG << 8) | curDescNum, 0, readLen, - dev->staticDeviceDescEndPtr, fetchConfigDescriptors); - } else - connectNewDevice(dev); - } else - killDevice(dev, ep); -} - -void requestDeviceDescriptor(IoRequest *req, u16 length); - -void requestDevDescrptCb(IoRequest *req) -{ - Endpoint *ep = req->correspEndpoint; - Device *dev = ep->correspDevice; - UsbDeviceDescriptor *desc = dev->staticDeviceDescPtr; - - if (req->resultCode == USB_RC_OK) { - if (req->transferedBytes < sizeof(UsbDeviceDescriptor)) { - ep->hcEd.maxPacketSize = (ep->hcEd.maxPacketSize & 0xF800) | desc->bMaxPacketSize0; - requestDeviceDescriptor(req, sizeof(UsbDeviceDescriptor)); - } else { - dev->fetchDescriptorCounter = 0; - dev->staticDeviceDescEndPtr = (u8 *)dev->staticDeviceDescEndPtr + sizeof(UsbDeviceDescriptor); - fetchConfigDescriptors(req); - } - } else { - dbg_printf("unable to read device descriptor, err %d\n", req->resultCode); - killDevice(dev, ep); - } -} - -void requestDeviceDescriptor(IoRequest *req, u16 length) -{ - Endpoint *ep = req->correspEndpoint; - Device *dev = ep->correspDevice; - - dev->staticDeviceDescEndPtr = dev->staticDeviceDescPtr; - - doControlTransfer(ep, &dev->ioRequest, - USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR, USB_DT_DEVICE << 8, 0, length, dev->staticDeviceDescEndPtr, - requestDevDescrptCb); -} - -void hubPeekDeviceDescriptor(IoRequest *req) -{ - requestDeviceDescriptor(req, 8); - - // we've assigned a function address to the device and can reset the next device now, if there is one - checkDelayedResets(req->correspEndpoint->correspDevice); -} - -void hubSetFuncAddress(Endpoint *ep); - -void hubSetFuncAddressCB(IoRequest *req) -{ - Endpoint *ep = req->correspEndpoint; - Device *dev = ep->correspDevice; - - if (req->resultCode == USB_RC_NORESPONSE) { - dbg_printf("device not responding\n"); - dev->functionDelay <<= 1; - if (dev->functionDelay <= 0x500) - addTimerCallback(&dev->timer, (TimerCallback)hubSetFuncAddress, ep, dev->functionDelay); - else - killDevice(dev, ep); - } else { - ep->hcEd.hcArea |= dev->functionAddress & 0x7F; - dev->deviceStatus = DEVICE_READY; - - addTimerCallback(&dev->timer, (TimerCallback)hubPeekDeviceDescriptor, req, 10); - } -} - -void hubSetFuncAddress(Endpoint *ep) -{ - Device *dev = ep->correspDevice; - - // printf("setting FA %02X\n", dev->functionAddress); - doControlTransfer(ep, &dev->ioRequest, - USB_DIR_OUT | USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS, dev->functionAddress, 0, 0, NULL, hubSetFuncAddressCB); -} - -int hubTimedSetFuncAddress(Device *dev) -{ - dev->functionDelay = 20; - addTimerCallback(&dev->timer, (TimerCallback)hubSetFuncAddress, dev->endpointListStart, 20); - return 0; -} - -void hubGetPortStatusCallback(IoRequest *req) -{ - UsbHub *dev = (UsbHub *)req->userCallbackArg; - Device *port; - if (req->resultCode == USB_RC_OK) { - int feature = -1; - - dbg_printf("port status change: %d: %08X\n", dev->portCounter, dev->portStatusChange); - if (dev->portStatusChange & BIT(C_PORT_CONNECTION)) - feature = C_PORT_CONNECTION; - else if (dev->portStatusChange & BIT(C_PORT_ENABLE)) - feature = C_PORT_ENABLE; - else if (dev->portStatusChange & BIT(C_PORT_SUSPEND)) - feature = C_PORT_SUSPEND; - else if (dev->portStatusChange & BIT(C_PORT_OVER_CURRENT)) - feature = C_PORT_OVER_CURRENT; - else if (dev->portStatusChange & BIT(C_PORT_RESET)) - feature = C_PORT_RESET; - - if (feature >= 0) { - dev->portStatusChange &= ~BIT(feature); - HubControlTransfer(dev, - USB_DIR_OUT | USB_RT_PORT, USB_REQ_CLEAR_FEATURE, feature, dev->portCounter, 0, NULL, - hubGetPortStatusCallback); - } else { - port = fetchPortElemByNumber(dev->controlEp->correspDevice, dev->portCounter); - if (port) { - if (dev->portStatusChange & BIT(PORT_CONNECTION)) { - dbg_printf("Hub Port CCS\n"); - if (port->deviceStatus == DEVICE_NOTCONNECTED) { - dbg_printf("resetting dev\n"); - port->deviceStatus = DEVICE_CONNECTED; - addTimerCallback(&port->timer, (TimerCallback)hubResetDevice, port, 500); - return; - } else if (port->deviceStatus == DEVICE_RESETPENDING) { - if (dev->portStatusChange & BIT(PORT_ENABLE)) { - dbg_printf("hub port reset done, opening control EP\n"); - port->deviceStatus = DEVICE_RESETCOMPLETE; - port->isLowSpeedDevice = (dev->portStatusChange >> PORT_LOW_SPEED) & 1; - - if (openDeviceEndpoint(port, NULL, 0)) - hubTimedSetFuncAddress(port); - else - dbg_printf("Can't open default control ep.\n"); - dev->hubStatusCounter = 0; - } - } - } else { - dbg_printf("disconnected; flushing port\n"); - flushPort(port); - } - } - hubStatusChangeCallback(&dev->statusIoReq); - } - } else - dbg_printf("HubGetPortStatusCallback res %d\n", req->resultCode); -} - -void getHubStatusChange(UsbHub *dev) -{ - if (dev->statusIoReq.busyFlag == 0) { - attachIoReqToEndpoint(dev->statusChangeEp, &dev->statusIoReq, - dev->statusChangeInfo, (dev->numChildDevices + 8) >> 3, hubStatusChangeCallback); - } else - dbg_printf("getHubStatusChange: StatusChangeEP IoReq is busy!\n"); -} - -void hubSetPortPower(IoRequest *req) -{ - UsbHub *dev = (UsbHub *)req->userCallbackArg; - - if ((req->resultCode == USB_RC_OK) || (dev->portCounter == 0)) { - // there is no result to check if this is the first call for this hub - dev->portCounter++; - if (dev->portCounter <= dev->numChildDevices) { - HubControlTransfer(dev, - USB_DIR_OUT | USB_RT_PORT, USB_REQ_SET_FEATURE, PORT_POWER, dev->portCounter, 0, NULL, - hubSetPortPower); - } else - getHubStatusChange(dev); - } -} - -void hubSetupPorts(IoRequest *req) -{ - UsbHub *dev = (UsbHub *)req->userCallbackArg; - Device *usbDev = dev->controlEp->correspDevice; - - if (req->resultCode == USB_RC_OK) { - int port; - - dev->hubStatusCounter = 0; - dev->portCounter = 0; - dev->numChildDevices = dev->desc.bNbrPorts; - for (port = 0; port < dev->desc.bNbrPorts; port++) { - if (!attachChildDevice(usbDev, port + 1)) { - dev->numChildDevices = port; - break; - } - } - if (dev->numChildDevices > 0) - hubSetPortPower(req); - } -} - -void hubCheckPorts(IoRequest *req) -{ - UsbHub *dev = (UsbHub *)req->userCallbackArg; - if (req->resultCode == USB_RC_OK) { - if (dev->desc.bNbrPorts <= usbConfig.maxPortsPerHub) { - HubControlTransfer(dev, - USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_STATUS, 0, 0, 4, - &dev->hubStatus, hubSetupPorts); - } else - dbg_printf("Hub has too many ports (%d > %d)\n", dev->desc.bNbrPorts, usbConfig.maxPortsPerHub); - } -} - -void hubCheckDeviceDesc(IoRequest *req) -{ - UsbHub *dev = (UsbHub *)req->userCallbackArg; - if (req->resultCode == USB_RC_OK) { - if (dev->desc.bDescriptorType == USB_DT_HUB) - hubCheckPorts(req); // we've got the descriptor already - else - HubControlTransfer(dev, - USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_DESCRIPTOR, USB_DT_HUB << 8, 0, sizeof(UsbHubDescriptor), &dev->desc, - hubCheckPorts); - } -} - -int hubDrvProbe(int devId) -{ - UsbDeviceDescriptor *devDesc; - devDesc = (UsbDeviceDescriptor *)doGetDeviceStaticDescriptor(devId, NULL, USB_DT_DEVICE); - - if (devDesc && (devDesc->bDeviceClass == USB_CLASS_HUB) && (devDesc->bNumConfigurations == 1)) - return 1; - else - return 0; -} - -int hubDrvConnect(int devId) -{ - UsbConfigDescriptor *confDesc; - UsbInterfaceDescriptor *intfDesc; - UsbEndpointDescriptor *endpDesc; - UsbHubDescriptor *hubDesc; - Device *dev; - UsbHub *hubDevice; - - dev = fetchDeviceById(devId); - if (!dev) - return -1; - - confDesc = doGetDeviceStaticDescriptor(devId, NULL, USB_DT_CONFIG); - if (!confDesc || (confDesc->bNumInterfaces != 1)) - return -2; - - intfDesc = doGetDeviceStaticDescriptor(devId, confDesc, USB_DT_INTERFACE); - if (!intfDesc || (intfDesc->bNumEndpoints != 1)) - return -3; - - endpDesc = doGetDeviceStaticDescriptor(devId, intfDesc, USB_DT_ENDPOINT); - if (!endpDesc) - return -4; - - if ((endpDesc->bEndpointAddress & USB_DIR_IN) == 0) - return -5; - - if ((endpDesc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) - return -6; - - hubDesc = doGetDeviceStaticDescriptor(devId, endpDesc, USB_DT_HUB); - - hubDevice = allocHubBuffer(); - if (!hubDevice) - return -8; - - dev->privDataField = hubDevice; - hubDevice->controlEp = dev->endpointListStart; - - hubDevice->statusChangeEp = doOpenEndpoint(dev, endpDesc, 0); - if (!hubDevice->statusChangeEp) { - freeHubBuffer(hubDevice); - return -9; - } - - hubDevice->controlIoReq.userCallbackArg = hubDevice; - hubDevice->statusIoReq.userCallbackArg = hubDevice; - - if (hubDesc) { - u8 len = hubDesc->bLength; - if (len > sizeof(UsbHubDescriptor)) - len = sizeof(UsbHubDescriptor); - memcpy(&hubDevice->desc, hubDesc, len); - } else - memset(&hubDevice->desc, 0, sizeof(UsbHubDescriptor)); - - HubControlTransfer(hubDevice, - USB_DIR_OUT, USB_REQ_SET_CONFIGURATION, confDesc->bConfigurationValue, 0, 0, NULL, - hubCheckDeviceDesc); - - return 0; + doRegisterDriver(&usbHubDriver, OldGP); + return 0; } -int hubDrvDisconnect(int devId) +void deinitHubDriver(void) { - Device *dev = fetchDeviceById(devId); - if (dev) { - freeHubBuffer((UsbHub *)dev->privDataField); - return 0; - } else - return -1; + doUnregisterDriver(&usbHubDriver); + FreeSysMemoryWrap(hubBufferListMemoryBuffer); } diff --git a/iop/usb/usbd/src/hub.h b/iop/usb/usbd/src/hub.h deleted file mode 100644 index 26f8cfd3d0c..00000000000 --- a/iop/usb/usbd/src/hub.h +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @file - * USB Driver function prototypes and constants. - */ - -#ifndef __HUB_H__ -#define __HUB_H__ - -#include "usbdpriv.h" - -int removeEndpointFromDevice(Device *dev, Endpoint *ep); -int initHubDriver(void); -void flushPort(Device *dev); -int addTimerCallback(TimerCbStruct *arg, TimerCallback func, void *cbArg, u32 delay); -void hubResetDevice(void *devp); -int hubTimedSetFuncAddress(Device *dev); - - -#endif // __HUB_H__ diff --git a/iop/usb/usbd/src/hub_resets.c b/iop/usb/usbd/src/hub_resets.c new file mode 100644 index 00000000000..16ce9c62163 --- /dev/null +++ b/iop/usb/usbd/src/hub_resets.c @@ -0,0 +1,106 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +void usbdRebootInner(void) +{ + memPool->m_ohciRegs->HcRhPortStatus[0] = BIT(PORT_RESET); + memPool->m_ohciRegs->HcRhPortStatus[1] = BIT(PORT_RESET); +} + +void hubResetDevice(UsbdDevice_t *dev) +{ + if ( memPool->m_delayResets ) + { + dev->m_deviceStatus = DEVICE_RESETDELAYED; + } + else + { + memPool->m_delayResets = 1; + dev->m_deviceStatus = DEVICE_RESETPENDING; + dev->m_resetFlag = 1; + if ( dev->m_parent == memPool->m_deviceTreeRoot ) // root hub port + memPool->m_ohciRegs->HcRhPortStatus[dev->m_attachedToPortNo - 1] = BIT(PORT_RESET); + else // normal hub port + hubResetDevicePort(dev); + } +} + +static int checkDelayedResetsTree(UsbdDevice_t *tree) +{ + UsbdDevice_t *dev; + + for ( dev = tree->m_childListStart; dev; dev = dev->m_next ) + { + if ( dev->m_deviceStatus == DEVICE_RESETDELAYED ) + { + hubResetDevice(dev); + return 1; + } + if ( dev->m_childListStart ) + { + if ( (u8)((int)dev->m_deviceStatus - 7) < 2u ) + { + if ( checkDelayedResetsTree(dev) != 0 ) + return 1; + } + } + } + return 0; +} + +int checkDelayedResets(UsbdDevice_t *dev) +{ + memPool->m_delayResets = 0; + dev->m_resetFlag = 0; + checkDelayedResetsTree(memPool->m_deviceTreeRoot); + return 0; +} + +void handleRhsc(void) +{ + u32 portNum; + UsbdDevice_t *port; + UsbdDevice_t *next; + + for ( portNum = 0, port = memPool->m_deviceTreeRoot->m_childListStart; port; portNum += 1, port = next ) + { + u32 status; + + next = port->m_next; + status = memPool->m_ohciRegs->HcRhPortStatus[portNum]; + memPool->m_ohciRegs->HcRhPortStatus[portNum] = C_PORT_FLAGS; // reset all flags + if ( (status & BIT(PORT_CONNECTION)) != 0 ) + { + if ( port->m_deviceStatus >= (unsigned int)DEVICE_CONNECTED && ((status & BIT(C_PORT_CONNECTION)) != 0) ) + flushPort(port); + if ( port->m_deviceStatus == DEVICE_NOTCONNECTED ) + { + port->m_deviceStatus = DEVICE_CONNECTED; + addTimerCallback(&port->m_timer, (TimerCallback)hubResetDevice, port, 501); + } + else if ( port->m_deviceStatus == DEVICE_RESETPENDING ) + { + if ( (status & BIT(PORT_RESET)) == 0 ) + { + port->m_deviceStatus = DEVICE_RESETCOMPLETE; + port->m_isLowSpeedDevice = (status & BIT(PORT_LOW_SPEED)) != 0; + if ( openDeviceEndpoint(port, NULL, 0) ) + hubTimedSetFuncAddress(port); + } + } + } + else + { + flushPort(port); + } + } +} diff --git a/iop/usb/usbd/src/imports.lst b/iop/usb/usbd/src/imports.lst index 918e0ba8f90..49ca6669c2c 100644 --- a/iop/usb/usbd/src/imports.lst +++ b/iop/usb/usbd/src/imports.lst @@ -1,48 +1,54 @@ -loadcore_IMPORTS_start -I_RegisterLibraryEntries -loadcore_IMPORTS_end - -stdio_IMPORTS_start -I_printf -stdio_IMPORTS_end - sysmem_IMPORTS_start I_AllocSysMemory +I_FreeSysMemory sysmem_IMPORTS_end -sysclib_IMPORTS_start -I_memcpy -I_memset -I_strtol -sysclib_IMPORTS_end +loadcore_IMPORTS_start +I_RegisterLibraryEntries +I_ReleaseLibraryEntries +loadcore_IMPORTS_end intrman_IMPORTS_start -I_DisableIntr -I_EnableIntr I_RegisterIntrHandler +I_ReleaseIntrHandler +I_EnableIntr +I_DisableIntr I_CpuSuspendIntr I_CpuResumeIntr intrman_IMPORTS_end -thsemap_IMPORTS_start -I_CreateSema -I_WaitSema -I_SignalSema -I_DeleteSema -thsemap_IMPORTS_end +stdio_IMPORTS_start +I_printf +stdio_IMPORTS_end + +thbase_IMPORTS_start +I_CreateThread +I_DeleteThread +I_StartThread +I_TerminateThread +I_ChangeThreadPriority +I_DelayThread +thbase_IMPORTS_end thevent_IMPORTS_start I_CreateEventFlag +I_DeleteEventFlag I_SetEventFlag I_iSetEventFlag I_WaitEventFlag thevent_IMPORTS_end -thbase_IMPORTS_start -I_CreateThread -I_StartThread -I_DeleteThread -I_DelayThread -I_ChangeThreadPriority -thbase_IMPORTS_end +thsemap_IMPORTS_start +I_CreateSema +I_DeleteSema +I_SignalSema +I_WaitSema +thsemap_IMPORTS_end + +sysclib_IMPORTS_start +I_bcopy +I_bzero +I_memset // added +I_memcpy // added +sysclib_IMPORTS_end diff --git a/iop/usb/usbd/src/interface.c b/iop/usb/usbd/src/interface.c deleted file mode 100644 index 7589d97a405..00000000000 --- a/iop/usb/usbd/src/interface.c +++ /dev/null @@ -1,452 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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 -#include -#ifdef DEBUG -#include -#endif - -#include "usbdpriv.h" -#include "driver.h" -#include "mem.h" -#include "hcd.h" -#include "usbio.h" - -extern UsbdConfig usbConfig; -extern int hcdTid; -extern int callbackTid; - -int sceUsbdRegisterLdd(sceUsbdLddOps *driver) -{ - int res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - -#if USE_GP_REGISTER - res = doRegisterDriver(driver, OldGP); -#else - res = doRegisterDriver(driver, NULL); -#endif - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdRegisterAutoloader(sceUsbdLddOps *drv) -{ - int res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - -#if USE_GP_REGISTER - res = doRegisterAutoLoader(drv, OldGP); -#else - res = doRegisterAutoLoader(drv, NULL); -#endif - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdUnregisterLdd(sceUsbdLddOps *driver) -{ - int res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - - res = doUnregisterDriver(driver); - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdUnregisterAutoloader(void) -{ - int res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - - res = doUnregisterAutoLoader(); - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -void *sceUsbdScanStaticDescriptor(int devId, void *data, u8 type) -{ - void *res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return NULL; - } - - res = doGetDeviceStaticDescriptor(devId, data, type); - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdGetDeviceLocation(int devId, u8 *path) -{ - Device *dev; - int res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - - dev = fetchDeviceById(devId); - if (dev) - res = doGetDeviceLocation(dev, path); - else - res = USB_RC_BADDEV; - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdSetPrivateData(int devId, void *data) -{ - Device *dev; - int res = USB_RC_OK; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - - dev = fetchDeviceById(devId); - if (dev) - dev->privDataField = data; - else - res = USB_RC_BADDEV; - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -void *sceUsbdGetPrivateData(int devId) -{ - Device *dev; - void *res = NULL; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return NULL; - } - - dev = fetchDeviceById(devId); - if (dev) - res = dev->privDataField; - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdOpenPipe(int devId, UsbEndpointDescriptor *desc) -{ - Device *dev; - Endpoint *ep; - int res = -1; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return -1; - } - - dev = fetchDeviceById(devId); - if (dev) { - ep = doOpenEndpoint(dev, desc, 0); - if (ep) - res = ep->id; - } - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdClosePipe(int id) -{ - Endpoint *ep; - int res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return -1; - } - - ep = fetchEndpointById(id); - if (ep) - res = doCloseEndpoint(ep); - else - res = USB_RC_BADPIPE; - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdTransferPipe(int id, void *data, u32 len, void *option, sceUsbdDoneCallback callback, void *cbArg) -{ - UsbDeviceRequest *ctrlPkt = (UsbDeviceRequest *)option; - IoRequest *req; - Endpoint *ep; - int res = 0; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - - ep = fetchEndpointById(id); - if (!ep) { - dbg_printf("sceUsbdTransferPipe: Endpoint %d not found\n", id); - res = USB_RC_BADPIPE; - } - - if ((res == 0) && data && len) { - if ((((u32)((u8 *)data + len - 1) >> 12) - ((u32)data >> 12)) > 1) - res = USB_RC_BADLENGTH; - else if (ep->alignFlag && ((u32)data & 3)) - res = USB_RC_BADALIGN; - else if ((ep->endpointType == TYPE_ISOCHRON) && ((ep->hcEd.maxPacketSize & 0x7FF) < len)) - res = USB_RC_BADLENGTH; - } - if (res == 0) { - req = allocIoRequest(); - if (!req) { - dbg_printf("Ran out of IoReqs\n"); - res = USB_RC_IOREQ; - } - } - if (res == 0) { - req->userCallbackProc = callback; - req->userCallbackArg = cbArg; -#if USE_GP_REGISTER - req->gpSeg = GetGP(); // gp of the calling module -#endif - if (ep->endpointType == TYPE_CONTROL) { - if (!ctrlPkt) { - res = USB_RC_BADOPTION; - freeIoRequest(req); - } else if (ctrlPkt->length != len) { - res = USB_RC_BADLENGTH; - freeIoRequest(req); - } else { - res = doControlTransfer(ep, req, - ctrlPkt->requesttype, ctrlPkt->request, ctrlPkt->value, ctrlPkt->index, ctrlPkt->length, - data, signalCallbackThreadFunc); - } - } else { - if (ep->endpointType == TYPE_ISOCHRON) - req->waitFrames = (u32)option; - res = attachIoReqToEndpoint(ep, req, data, len, signalCallbackThreadFunc); - } - } - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdOpenPipeAligned(int devId, UsbEndpointDescriptor *desc) -{ - Device *dev; - Endpoint *ep; - int res = -1; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return -1; - } - - dev = fetchDeviceById(devId); - if (dev) { - ep = doOpenEndpoint(dev, desc, 1); - if (ep) - res = ep->id; - } - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} - -int sceUsbdChangeThreadPriority(int prio1, int prio2) -{ - int res; -#if USE_GP_REGISTER - void *OldGP; - - OldGP = SetModuleGP(); -#endif - if (usbdLock() != 0) { -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - return USB_RC_BADCONTEXT; - } - - res = 0; - - if (usbConfig.hcdThreadPrio != prio1) { - usbConfig.hcdThreadPrio = prio1; - res = ChangeThreadPriority(hcdTid, prio1); - } - - if (usbConfig.cbThreadPrio != prio2) { - usbConfig.cbThreadPrio = prio2; - res = ChangeThreadPriority(callbackTid, prio2); - } - - usbdUnlock(); -#if USE_GP_REGISTER - SetGP(OldGP); -#endif - - return res; -} diff --git a/iop/usb/usbd/src/io_request.c b/iop/usb/usbd/src/io_request.c new file mode 100644 index 00000000000..dc5d518828e --- /dev/null +++ b/iop/usb/usbd/src/io_request.c @@ -0,0 +1,366 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +static int setupControlTransfer(UsbdEndpoint_t *ep) +{ + UsbdIoRequest_t *curIoReq; + UsbdHcTD_t *dataTd; + UsbdHcTD_t *tailTd; + UsbdHcTD_t *statusTd; + + if ( !ep->m_hcEd->m_tdTail || ED_HALTED(*(ep->m_hcEd)) || ED_SKIPPED(*(ep->m_hcEd)) || !ep->m_ioReqListStart ) + { + // endpoint error + if ( ep->m_inTdQueue == NOTIN_QUEUE ) + return 0; + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + { + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + } + else + { + memPool->m_tdQueueStart = ep->m_busyNext; + } + ep->m_inTdQueue = NOTIN_QUEUE; + return 0; + } + curIoReq = ep->m_ioReqListStart; + dataTd = NULL; + if ( curIoReq->m_destPtr && (int)curIoReq->m_length > 0 ) + { + dataTd = allocTd(); + if ( !dataTd ) + { + if ( ep->m_inTdQueue != NOTIN_QUEUE ) + return 0; + ep->m_busyPrev = memPool->m_tdQueueEnd; + if ( memPool->m_tdQueueEnd ) + { + memPool->m_tdQueueEnd->m_busyNext = ep; + } + else + { + memPool->m_tdQueueStart = ep; + } + ep->m_busyNext = NULL; + memPool->m_tdQueueEnd = ep; + ep->m_inTdQueue = GENTD_QUEUE; + return 0; + } + } + statusTd = allocTd(); + tailTd = allocTd(); + if ( !statusTd || !tailTd ) + { + freeTd(dataTd); + freeTd(statusTd); + freeTd(tailTd); + if ( ep->m_inTdQueue != NOTIN_QUEUE ) + return 0; + ep->m_busyPrev = memPool->m_tdQueueEnd; + if ( memPool->m_tdQueueEnd ) + { + memPool->m_tdQueueEnd->m_busyNext = ep; + } + else + { + memPool->m_tdQueueStart = ep; + } + ep->m_busyNext = NULL; + memPool->m_tdQueueEnd = ep; + ep->m_inTdQueue = GENTD_QUEUE; + return 0; + } + if ( curIoReq->m_next ) + curIoReq->m_next->m_prev = curIoReq->m_prev; + else + ep->m_ioReqListEnd = curIoReq->m_prev; + if ( curIoReq->m_prev ) + curIoReq->m_prev->m_next = curIoReq->m_next; + else + ep->m_ioReqListStart = curIoReq->m_next; + // first stage: setup + ep->m_hcEd->m_tdTail->m_hcArea = TD_HCAREA(USB_RC_NOTACCESSED, 2, 7, TD_SETUP, 0) << 16; + ep->m_hcEd->m_tdTail->m_curBufPtr = &curIoReq->m_devReq; + ep->m_hcEd->m_tdTail->m_next = dataTd ? dataTd : statusTd; + ep->m_hcEd->m_tdTail->m_bufferEnd = ((u8 *)&curIoReq->m_devReq) + sizeof(UsbDeviceRequest) - 1; + memPool->m_hcTdToIoReqLUT[ep->m_hcEd->m_tdTail - memPool->m_hcTdBuf] = curIoReq; + // second stage: data + if ( dataTd ) + { + dataTd->m_hcArea = (curIoReq->m_devReq.requesttype & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ? + (TD_HCAREA(USB_RC_NOTACCESSED, 3, 7, TD_OUT, 1) << 16) : + (TD_HCAREA(USB_RC_NOTACCESSED, 3, 7, TD_IN, 1) << 16); + dataTd->m_next = statusTd; + dataTd->m_curBufPtr = curIoReq->m_destPtr; + dataTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + curIoReq->m_length - 1; + memPool->m_hcTdToIoReqLUT[dataTd - memPool->m_hcTdBuf] = curIoReq; + } + // third stage: status + statusTd->m_hcArea = (curIoReq->m_devReq.requesttype & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ? + (TD_HCAREA(USB_RC_NOTACCESSED, 3, 0, TD_IN, 0) << 16) : + (TD_HCAREA(USB_RC_NOTACCESSED, 3, 0, TD_OUT, 0) << 16); + statusTd->m_curBufPtr = NULL; + statusTd->m_next = tailTd; + statusTd->m_bufferEnd = NULL; + memPool->m_hcTdToIoReqLUT[statusTd - memPool->m_hcTdBuf] = curIoReq; + ep->m_hcEd->m_tdTail = tailTd; + memPool->m_ohciRegs->HcCommandStatus |= OHCI_COM_CLF; // control list filled + if ( ep->m_ioReqListStart ) + { + return 1; + } + if ( ep->m_inTdQueue == NOTIN_QUEUE ) + { + return 1; + } + // remove endpoint from busy list if there are no IoRequests left + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + else + memPool->m_tdQueueStart = ep->m_busyNext; + ep->m_inTdQueue = NOTIN_QUEUE; + return 1; +} + +static int setupIsocronTransfer(UsbdEndpoint_t *ep) +{ + UsbdHcED_t *ed; + UsbdIoRequest_t *curIoReq; + UsbdHcIsoTD_t *curTd; + UsbdHcIsoTD_t *newTd; + u16 frameNo; + + ed = ep->m_hcEd; + if ( !ed->m_tdTail || ED_HALTED(*ed) || ED_SKIPPED(*ed) || !ep->m_ioReqListStart ) + { + // endpoint error + if ( ep->m_inTdQueue == NOTIN_QUEUE ) + return 0; + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + { + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + } + else + { + memPool->m_tdQueueStart = ep->m_busyNext; + } + ep->m_inTdQueue = NOTIN_QUEUE; + return 0; + } + curIoReq = ep->m_ioReqListStart; + curTd = (UsbdHcIsoTD_t *)ed->m_tdTail; + newTd = allocIsoTd(); + if ( !newTd ) + { + if ( ep->m_inTdQueue != NOTIN_QUEUE ) + return 0; + ep->m_busyPrev = memPool->m_tdQueueEnd; + if ( memPool->m_tdQueueEnd ) + memPool->m_tdQueueEnd->m_busyNext = ep; + else + memPool->m_tdQueueStart = ep; + ep->m_busyNext = NULL; + memPool->m_tdQueueEnd = ep; + ep->m_inTdQueue = ISOTD_QUEUE; + return 0; + } + if ( curIoReq->m_next ) + curIoReq->m_next->m_prev = curIoReq->m_prev; + else + ep->m_ioReqListEnd = curIoReq->m_prev; + if ( curIoReq->m_prev ) + curIoReq->m_prev->m_next = curIoReq->m_next; + else + ep->m_ioReqListStart = curIoReq->m_next; + if ( (UsbdHcTD_t *)((uiptr)ed->m_tdHead & ~0xF) == ed->m_tdTail ) + frameNo = (memPool->m_hcHCCA->FrameNumber + 2) & 0xFFFF; + else + frameNo = (ep->m_isochronLastFrameNum) & 0xFFFF; + frameNo = (u16)(frameNo + (curIoReq->m_waitFrames & 0xFFFF)); + ep->m_isochronLastFrameNum = (curIoReq->m_req.bNumPackets ? (curIoReq->m_req.bNumPackets & 0xFFFF) : 1) + frameNo; + if ( curIoReq->m_req.bNumPackets ) + { + int psw0_tmp; + int i; + + curTd->m_hcArea = ((curIoReq->m_req.bNumPackets - 1) << 24) | frameNo | (USB_RC_NOTACCESSED << 28); + curTd->m_next = newTd; + curTd->m_bufferPage0 = (void *)((uiptr)curIoReq->m_destPtr & ~0xFFF); + curTd->m_bufferEnd = NULL; + if ( curIoReq->m_destPtr && (int)(curIoReq->m_length) > 0 ) + { + curTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + ((int)curIoReq->m_length - 1); + } + psw0_tmp = ((uiptr)curIoReq->m_destPtr & 0xFFF) | (USB_RC_NOTACCESSED << 12); + for ( i = 0; i < (int)curIoReq->m_req.bNumPackets; i += 1 ) + { + curTd->m_psw[i] = psw0_tmp; + psw0_tmp += curIoReq->m_req.Packets[i].bLength; + } + } + else + { + curTd->m_hcArea = frameNo | (USB_RC_NOTACCESSED << 28); + curTd->m_next = newTd; + curTd->m_bufferPage0 = (void *)((uiptr)curIoReq->m_destPtr & ~0xFFF); + curTd->m_bufferEnd = NULL; + if ( curIoReq->m_destPtr && (int)(curIoReq->m_length) > 0 ) + { + curTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + ((int)curIoReq->m_length - 1); + } + curTd->m_psw[0] = ((uiptr)curIoReq->m_destPtr & 0xFFF) | (USB_RC_NOTACCESSED << 12); + } + memPool->m_hcIsoTdToIoReqLUT[curTd - memPool->m_hcIsoTdBuf] = curIoReq; + ed->m_tdTail = (UsbdHcTD_t *)newTd; + if ( ep->m_ioReqListStart ) + { + return 1; + } + if ( ep->m_inTdQueue == NOTIN_QUEUE ) + { + return 1; + } + // remove endpoint from busy list if there are no IoRequests left + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + else + memPool->m_tdQueueStart = ep->m_busyNext; + ep->m_inTdQueue = NOTIN_QUEUE; + return 1; +} + +static int setupBulkTransfer(UsbdEndpoint_t *ep) +{ + UsbdHcED_t *ed; + UsbdIoRequest_t *curIoReq; + UsbdHcTD_t *curTd; + UsbdHcTD_t *newTd; + + ed = ep->m_hcEd; + if ( !ed->m_tdTail || ED_HALTED(*ed) || ED_SKIPPED(*ed) || !ep->m_ioReqListStart ) + { + // endpoint error + dbg_printf("ERROR UsbdEndpoint_t error\n"); + if ( ep->m_inTdQueue == NOTIN_QUEUE ) + return 0; + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + { + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + } + else + { + memPool->m_tdQueueStart = ep->m_busyNext; + } + ep->m_inTdQueue = NOTIN_QUEUE; + return 0; + } + curIoReq = ep->m_ioReqListStart; + curTd = ed->m_tdTail; + newTd = allocTd(); + if ( !newTd ) + { + if ( ep->m_inTdQueue != NOTIN_QUEUE ) + return 0; + ep->m_busyPrev = memPool->m_tdQueueEnd; + if ( memPool->m_tdQueueEnd ) + memPool->m_tdQueueEnd->m_busyNext = ep; + else + memPool->m_tdQueueStart = ep; + ep->m_busyNext = NULL; + memPool->m_tdQueueEnd = ep; + ep->m_inTdQueue = GENTD_QUEUE; + return 0; + } + if ( curIoReq->m_next ) + curIoReq->m_next->m_prev = curIoReq->m_prev; + else + ep->m_ioReqListEnd = curIoReq->m_prev; + if ( curIoReq->m_prev ) + curIoReq->m_prev->m_next = curIoReq->m_next; + else + ep->m_ioReqListStart = curIoReq->m_next; + curTd->m_hcArea = TD_HCAREA(USB_RC_NOTACCESSED, 0, 0, 3, 1) << 16; + curTd->m_next = newTd; + curTd->m_curBufPtr = curIoReq->m_destPtr; + curTd->m_bufferEnd = NULL; + if ( curIoReq->m_destPtr && (int)curIoReq->m_length > 0 ) + { + curTd->m_bufferEnd = (u8 *)curIoReq->m_destPtr + ((int)curIoReq->m_length - 1); + } + memPool->m_hcTdToIoReqLUT[curTd - memPool->m_hcTdBuf] = curIoReq; + ed->m_tdTail = newTd; + if ( ep->m_endpointType == TYPE_BULK ) + memPool->m_ohciRegs->HcCommandStatus |= OHCI_COM_BLF; // Bulk List Filled + if ( ep->m_ioReqListStart ) + { + return 1; + } + if ( ep->m_inTdQueue == NOTIN_QUEUE ) + { + return 1; + } + // remove endpoint from busy list if there are no IoRequests left + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + else + memPool->m_tdQueueStart = ep->m_busyNext; + ep->m_inTdQueue = NOTIN_QUEUE; + return 1; +} + +void handleIoReqList(UsbdEndpoint_t *ep) +{ + switch ( ep->m_endpointType ) + { + case TYPE_CONTROL: + { + setupControlTransfer(ep); + break; + } + case TYPE_ISOCHRON: + { + setupIsocronTransfer(ep); + break; + } + case TYPE_BULK: + default: // bulk or interrupt + { + setupBulkTransfer(ep); + break; + } + } +} diff --git a/iop/usb/usbd/src/irx_imports.h b/iop/usb/usbd/src/irx_imports.h index c17d71f091d..7d1ce97d284 100644 --- a/iop/usb/usbd/src/irx_imports.h +++ b/iop/usb/usbd/src/irx_imports.h @@ -3,7 +3,7 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright ps2dev - http://www.ps2dev.org # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. # @@ -13,18 +13,17 @@ #ifndef IOP_IRX_IMPORTS_H #define IOP_IRX_IMPORTS_H -#include "irx.h" +#include /* Please keep these in alphabetical order! */ -#include "intrman.h" -#include "loadcore.h" -#include "stdio.h" -#include "sysclib.h" -#include "sysmem.h" -#include "thbase.h" -#include "thevent.h" -#include "thmsgbx.h" -#include "thsemap.h" -#include "vblank.h" + +#include +#include +#include +#include +#include +#include +#include +#include #endif /* IOP_IRX_IMPORTS_H */ diff --git a/iop/usb/usbd/src/mem.c b/iop/usb/usbd/src/mem.c index 29425e207f3..a852a38e517 100644 --- a/iop/usb/usbd/src/mem.c +++ b/iop/usb/usbd/src/mem.c @@ -3,257 +3,300 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright 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 "mem.h" - -#include "stdio.h" - -MemoryPool memPool; - -HcIsoTD *allocIsoTd(void) -{ - HcIsoTD *newTd = memPool.freeHcIsoTdList; - if (newTd) { - memPool.freeHcIsoTdList = newTd->next; - newTd->next = NULL; - } - return newTd; -} -void freeIsoTd(HcIsoTD *argTd) +UsbdDevice_t *fetchDeviceById(int devId) { - HcIsoTD *pos; - if (argTd) { - for (pos = memPool.freeHcIsoTdList; pos != NULL; pos = pos->next) - if (pos == argTd) { - printf("freeIsoTd %p: already free\n", argTd); - return; - } - argTd->next = memPool.freeHcIsoTdList; - memPool.freeHcIsoTdList = argTd; - } + UsbdDevice_t *dev; + + if ( devId <= 0 ) + { + return NULL; + } + if ( devId >= usbConfig.m_maxDevices ) + { + return NULL; + } + dev = &memPool->m_deviceTreeBuf[devId]; + if ( !dev->m_parent ) + return NULL; + return dev; } -HcTD *allocTd(void) +UsbdEndpoint_t *fetchEndpointById(int id) { - HcTD *res = memPool.freeHcTdList; - if (res) { - memPool.freeHcTdList = res->next; - res->next = NULL; - } - return res; + UsbdEndpoint_t *ep; + + if ( id < 0 ) + { + return NULL; + } + if ( id >= usbConfig.m_maxEndpoints ) + { + return NULL; + } + ep = &memPool->m_endpointBuf[id]; + if ( !ep->m_correspDevice ) + return NULL; + return ep; } -void freeTd(HcTD *argTd) +UsbdDevice_t *getDeviceTreeRoot(void) { - HcTD *pos; - if (argTd) { - for (pos = memPool.freeHcTdList; pos != NULL; pos = pos->next) - if (pos == argTd) { - printf("FreeTD %p: already free\n", argTd); - return; - } - argTd->next = memPool.freeHcTdList; - memPool.freeHcTdList = argTd; - } + return memPool->m_deviceTreeRoot; } -Device *attachChildDevice(Device *parent, u32 portNum) +UsbdDevice_t *attachChildDevice(UsbdDevice_t *parent, u32 portNum) { - Device *newDev = memPool.freeDeviceListStart; - if (!newDev) { - dbg_printf("Ran out of device handles\n"); - return NULL; - } - - if (newDev->next) - newDev->next->prev = newDev->prev; - else - memPool.freeDeviceListEnd = newDev->prev; - - if (newDev->prev) - newDev->prev->next = newDev->next; - else - memPool.freeDeviceListStart = newDev->next; - - newDev->endpointListEnd = newDev->endpointListStart = NULL; - newDev->devDriver = NULL; - newDev->deviceStatus = DEVICE_NOTCONNECTED; - newDev->resetFlag = 0; - newDev->childListEnd = newDev->childListStart = NULL; - newDev->parent = parent; - newDev->attachedToPortNo = portNum; - newDev->privDataField = NULL; - if (parent) { - newDev->prev = parent->childListEnd; - if (parent->childListEnd) - parent->childListEnd->next = newDev; - else - parent->childListStart = newDev; - newDev->next = NULL; - parent->childListEnd = newDev; - } else - newDev->next = newDev->prev = NULL; - return newDev; + UsbdDevice_t *newDev; + + newDev = memPool->m_freeDeviceListStart; + if ( !newDev ) + { + dbg_printf("Ran out of device handles\n"); + return NULL; + } + if ( newDev->m_next ) + newDev->m_next->m_prev = newDev->m_prev; + else + memPool->m_freeDeviceListEnd = newDev->m_prev; + if ( newDev->m_prev ) + newDev->m_prev->m_next = newDev->m_next; + else + memPool->m_freeDeviceListStart = newDev->m_next; + newDev->m_endpointListEnd = NULL; + newDev->m_endpointListStart = NULL; + newDev->m_devDriver = NULL; + newDev->m_deviceStatus = DEVICE_NOTCONNECTED; + newDev->m_resetFlag = 0; + newDev->m_magicPowerValue = 0; + newDev->m_childListEnd = NULL; + newDev->m_childListStart = NULL; + newDev->m_parent = parent; + newDev->m_attachedToPortNo = portNum; + newDev->m_privDataField = NULL; + if ( parent ) + { + newDev->m_prev = parent->m_childListEnd; + if ( parent->m_childListEnd ) + parent->m_childListEnd->m_next = newDev; + else + parent->m_childListStart = newDev; + newDev->m_next = NULL; + parent->m_childListEnd = newDev; + } + return newDev; } -void freeDevice(Device *dev) +void freeDevice(UsbdDevice_t *dev) { - if (!dev) - return; - - if ((dev < memPool.deviceTreeBuf) || (dev >= memPool.deviceTreeBuf + usbConfig.maxDevices)) { - printf("freeDevice %p: Arg is not part of dev buffer\n", dev); - return; - } - - dev->prev = memPool.freeDeviceListEnd; - if (memPool.freeDeviceListEnd) - memPool.freeDeviceListEnd->next = dev; - else - memPool.freeDeviceListStart = dev; - - dev->next = NULL; - dev->parent = NULL; - memPool.freeDeviceListEnd = dev; + if ( !dev || dev < memPool->m_deviceTreeBuf || dev >= memPool->m_deviceTreeBuf + usbConfig.m_maxDevices ) + { + dbg_printf("freeDevice %p: Arg is not part of dev buffer\n", dev); + return; + } + dev->m_prev = memPool->m_freeDeviceListEnd; + if ( memPool->m_freeDeviceListEnd ) + memPool->m_freeDeviceListEnd->m_next = dev; + else + memPool->m_freeDeviceListStart = dev; + dev->m_next = NULL; + memPool->m_freeDeviceListEnd = dev; + dev->m_parent = NULL; } -Device *fetchPortElemByNumber(Device *hub, int port) +UsbdIoRequest_t *allocIoRequest(void) { - Device *res = hub->childListStart; - while (--port > 0) { - if (!res) - return NULL; - res = res->next; - } - return res; + UsbdIoRequest_t *res; + + res = memPool->m_freeIoReqList; + if ( !res ) + { + dbg_printf("ran out of IoReqs\n"); + return NULL; + } + if ( res->m_next ) + res->m_next->m_prev = res->m_prev; + else + memPool->m_freeIoReqListEnd = res->m_prev; + if ( res->m_prev ) + res->m_prev->m_next = res->m_next; + else + memPool->m_freeIoReqList = res->m_next; + return res; } -void addToHcEndpointList(u8 type, HcED *ed) +void freeIoRequest(UsbdIoRequest_t *req) { - ed->next = memPool.hcEdBuf[type].next; - memPool.hcEdBuf[type].next = ed; + UsbdIoRequest_t *pos; + + if ( !req ) + { + return; + } + if ( req < memPool->m_ioReqBufPtr || req >= memPool->m_ioReqBufPtr + usbConfig.m_maxIoReqs ) + { + req->m_busyFlag = 0; + return; + } + for ( pos = memPool->m_freeIoReqList; pos && pos != req; pos = pos->m_next ) + { + } + if ( pos ) + { + dbg_printf("freeIoRequest %p: already free.\n", req); + return; + } + req->m_busyFlag = 0; + req->m_prev = memPool->m_freeIoReqListEnd; + if ( memPool->m_freeIoReqListEnd ) + memPool->m_freeIoReqListEnd->m_next = req; + else + memPool->m_freeIoReqList = req; + req->m_next = NULL; + memPool->m_freeIoReqListEnd = req; } -void removeHcEdFromList(int type, const HcED *hcEd) +UsbdEndpoint_t *allocEndpointForDevice(UsbdDevice_t *dev, u32 align) { - HcED *prev = memPool.hcEdBuf + type; - HcED *pos = prev->next; - while (pos) { - if (pos == hcEd) { - prev->next = pos->next; - return; - } - prev = pos; - pos = pos->next; - } + UsbdEndpoint_t *newEp; + + newEp = memPool->m_freeEpListStart; + if ( !newEp ) + { + return NULL; + } + if ( newEp->m_next ) + newEp->m_next->m_prev = newEp->m_prev; + else + memPool->m_freeEpListEnd = newEp->m_prev; + if ( newEp->m_prev ) + newEp->m_prev->m_next = newEp->m_next; + else + memPool->m_freeEpListStart = newEp->m_next; + newEp->m_correspDevice = dev; + newEp->m_ioReqListEnd = NULL; + newEp->m_ioReqListStart = NULL; + newEp->m_busyPrev = NULL; + newEp->m_busyNext = NULL; + newEp->m_inTdQueue = 0; + newEp->m_alignFlag = align; + newEp->m_prev = dev->m_endpointListEnd; + if ( dev->m_endpointListEnd ) + dev->m_endpointListEnd->m_next = newEp; + else + dev->m_endpointListStart = newEp; + newEp->m_next = NULL; + dev->m_endpointListEnd = newEp; + return newEp; } -Endpoint *allocEndpointForDevice(Device *dev, u32 align) +int cleanUpFunc(UsbdDevice_t *dev, UsbdEndpoint_t *ep) { - Endpoint *newEp = memPool.freeEpListStart; - if (!newEp) - return NULL; - - if (newEp->next) - newEp->next->prev = newEp->prev; - else - memPool.freeEpListEnd = newEp->prev; - - if (newEp->prev) - newEp->prev->next = newEp->next; - else - memPool.freeEpListStart = newEp->next; - - newEp->correspDevice = dev; - newEp->ioReqListStart = newEp->ioReqListEnd = NULL; - newEp->busyNext = newEp->busyPrev = NULL; - newEp->inTdQueue = 0; - newEp->alignFlag = align; - - newEp->next = NULL; - newEp->prev = dev->endpointListEnd; - if (dev->endpointListEnd) - dev->endpointListEnd->next = newEp; - else - dev->endpointListStart = newEp; - - dev->endpointListEnd = newEp; - return newEp; + if ( !ep || ep < memPool->m_endpointBuf || ep >= memPool->m_endpointBuf + usbConfig.m_maxEndpoints ) + { + return 0; + } + if ( ep->m_inTdQueue != NOTIN_QUEUE ) + { + if ( ep->m_busyNext ) + ep->m_busyNext->m_busyPrev = ep->m_busyPrev; + else + memPool->m_tdQueueEnd = ep->m_busyPrev; + if ( ep->m_busyPrev ) + ep->m_busyPrev->m_busyNext = ep->m_busyNext; + else + memPool->m_tdQueueStart = ep->m_busyNext; + ep->m_inTdQueue = NOTIN_QUEUE; + } + if ( ep->m_next ) + ep->m_next->m_prev = ep->m_prev; + else + dev->m_endpointListEnd = ep->m_prev; + if ( ep->m_prev ) + ep->m_prev->m_next = ep->m_next; + else + dev->m_endpointListStart = ep->m_next; + ep->m_prev = memPool->m_freeEpListEnd; + if ( memPool->m_freeEpListEnd ) + memPool->m_freeEpListEnd->m_next = ep; + else + memPool->m_freeEpListStart = ep; + ep->m_next = NULL; + memPool->m_freeEpListEnd = ep; + ep->m_correspDevice = NULL; + return 0; } -Device *fetchDeviceById(int devId) +UsbdHcTD_t *allocTd(void) { - if ((devId > 0) && (devId < usbConfig.maxDevices)) { - Device *dev; - - dev = memPool.deviceTreeBuf + devId; - if (dev->parent) - return dev; - } - return NULL; + UsbdHcTD_t *res; + + res = memPool->m_freeHcTdList; + if ( !res ) + { + return NULL; + } + memPool->m_freeHcTdList = res->m_next; + res->m_next = NULL; + return res; } -Endpoint *fetchEndpointById(int id) +void freeTd(UsbdHcTD_t *argTd) { - if ((id >= 0) && (id < usbConfig.maxEndpoints)) { - Endpoint *res; - - res = memPool.endpointBuf + id; - if (res->correspDevice) - return res; - } - return NULL; + UsbdHcTD_t *pos; + + if ( !argTd ) + { + return; + } + for ( pos = memPool->m_freeHcTdList; pos && argTd != pos; pos = pos->m_next ) + { + } + if ( pos ) + { + dbg_printf("FreeTD %p: already free\n", argTd); + return; + } + argTd->m_next = memPool->m_freeHcTdList; + memPool->m_freeHcTdList = argTd; } -IoRequest *allocIoRequest(void) +UsbdHcIsoTD_t *allocIsoTd(void) { - IoRequest *res = memPool.freeIoReqList; - if (res) { - if (res->next) - res->next->prev = res->prev; - else - memPool.freeIoReqListEnd = res->prev; - - if (res->prev) - res->prev->next = res->next; - else - memPool.freeIoReqList = res->next; - res->prev = res->next = NULL; - } else - dbg_printf("ran out of IoReqs\n"); - return res; + UsbdHcIsoTD_t *newTd; + + newTd = memPool->m_freeHcIsoTdList; + if ( !newTd ) + { + return NULL; + } + memPool->m_freeHcIsoTdList = newTd->m_next; + newTd->m_next = NULL; + return newTd; } -void freeIoRequest(IoRequest *req) +void freeIsoTd(UsbdHcIsoTD_t *argTd) { - int num = req - memPool.ioReqBufPtr; - IoRequest *pos; - if (req) { - if ((num >= 0) && (num < usbConfig.maxIoReqs)) { - for (pos = memPool.freeIoReqList; pos != NULL; pos = pos->next) - if (pos == req) { - printf("freeIoRequest %p: already free.\n", req); - return; - } - req->prev = memPool.freeIoReqListEnd; - if (memPool.freeIoReqListEnd) - memPool.freeIoReqListEnd->next = req; - else - memPool.freeIoReqList = req; - req->next = NULL; - memPool.freeIoReqListEnd = req; - } - req->busyFlag = 0; - } + UsbdHcIsoTD_t *pos; + + if ( !argTd ) + { + return; + } + for ( pos = memPool->m_freeHcIsoTdList; pos && argTd != pos; pos = pos->m_next ) + { + } + if ( pos ) + { + dbg_printf("freeIsoTd %p: already free\n", argTd); + return; + } + argTd->m_next = memPool->m_freeHcIsoTdList; + memPool->m_freeHcIsoTdList = argTd; } diff --git a/iop/usb/usbd/src/mem.h b/iop/usb/usbd/src/mem.h deleted file mode 100644 index c2aa2859e00..00000000000 --- a/iop/usb/usbd/src/mem.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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 __MEM_H__ -#define __MEM_H__ - -#include "usbdpriv.h" - -extern MemoryPool memPool; - -HcIsoTD *allocIsoTd(void); -void freeIsoTd(HcIsoTD *argTd); - -HcTD *allocTd(void); -void freeTd(HcTD *argTd); - -Device *attachChildDevice(Device *parent, u32 portNum); -void freeDevice(Device *dev); - -Device *fetchPortElemByNumber(Device *hub, int port); - -void addToHcEndpointList(u8 type, HcED *ed); -void removeHcEdFromList(int type, const HcED *hcEd); - -Endpoint *allocEndpointForDevice(Device *dev, u32 align); - -Device *fetchDeviceById(int devId); -Endpoint *fetchEndpointById(int id); - -IoRequest *allocIoRequest(void); -void freeIoRequest(IoRequest *req); - -#endif diff --git a/iop/usb/usbd/src/report_descriptor_init.c b/iop/usb/usbd/src/report_descriptor_init.c new file mode 100644 index 00000000000..aacc35cc61d --- /dev/null +++ b/iop/usb/usbd/src/report_descriptor_init.c @@ -0,0 +1,116 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +int handleStaticDeviceDescriptor(UsbdDevice_t *dev, UsbDeviceDescriptor *devDescStart, UsbDeviceDescriptor *devDescEnd) +{ + UsbDeviceDescriptor *devDescCur; + u32 ifNum; + unsigned int bLength; + int i; + u32 wItemLength; + UsbdReportDescriptor_t *hidDescriptor; + int state; + u32 cfgNum; + UsbHidDescriptor *usbHidDescriptor; + const UsbConfigDescriptor *usbConfigDescriptor; + const UsbInterfaceDescriptor *usbInterfaceDescriptor; + + dev->m_reportDescriptorStart = NULL; + dev->m_reportDescriptorEnd = NULL; + cfgNum = 0; + ifNum = 0; + for ( devDescCur = devDescStart; devDescCur < devDescEnd; + devDescCur = (UsbDeviceDescriptor *)((u8 *)devDescCur + bLength) ) + { + bLength = devDescCur->bLength; + if ( bLength < 2 ) + break; + if ( (u8 *)devDescEnd - (u8 *)devDescCur < (int)bLength ) + break; + switch ( devDescCur->bDescriptorType ) + { + case 1u: + case 3u: + case 5u: + case 6u: + case 7u: + case 8u: + case 9u: + case 0xAu: + case 0xBu: + case 0xCu: + case 0xDu: + case 0xEu: + case 0xFu: + case 0x10u: + case 0x11u: + case 0x12u: + case 0x13u: + case 0x14u: + case 0x15u: + case 0x16u: + case 0x17u: + case 0x18u: + case 0x19u: + case 0x1Au: + case 0x1Bu: + case 0x1Cu: + case 0x1Du: + case 0x1Eu: + case 0x1Fu: + case 0x20u: + break; + case 2u: + if ( (int)bLength >= 9 ) + { + usbConfigDescriptor = (UsbConfigDescriptor *)devDescCur; + cfgNum = usbConfigDescriptor->bConfigurationValue; + } + break; + case 4u: + if ( (int)bLength >= 9 ) + { + usbInterfaceDescriptor = (UsbInterfaceDescriptor *)devDescCur; + ifNum = usbInterfaceDescriptor->bInterfaceNumber; + } + break; + case 0x21u: + usbHidDescriptor = (UsbHidDescriptor *)devDescCur; + for ( i = 0; i < usbHidDescriptor->bNumDescriptors; i += 1 ) + { + if ( usbHidDescriptor->items[i].bDescriptorType == 0x22 ) + { + wItemLength = + usbHidDescriptor->items[i].wDescriptorLengthLb + (usbHidDescriptor->items[i].wDescriptorLengthHb << 8); + CpuSuspendIntr(&state); + hidDescriptor = + (UsbdReportDescriptor_t *)AllocSysMemory(ALLOC_FIRST, wItemLength + sizeof(UsbdReportDescriptor_t), NULL); + CpuResumeIntr(state); + hidDescriptor->m_ifNum = ifNum; + hidDescriptor->m_length = wItemLength; + hidDescriptor->m_cfgNum = cfgNum; + hidDescriptor->m_prev = dev->m_reportDescriptorEnd; + if ( dev->m_reportDescriptorEnd ) + dev->m_reportDescriptorEnd->m_next = hidDescriptor; + else + dev->m_reportDescriptorStart = hidDescriptor; + hidDescriptor->m_next = NULL; + dev->m_reportDescriptorEnd = hidDescriptor; + } + } + break; + default: + break; + } + } + return 0; +} diff --git a/iop/usb/usbd/src/td_queue.c b/iop/usb/usbd/src/td_queue.c new file mode 100644 index 00000000000..0079dcf186c --- /dev/null +++ b/iop/usb/usbd/src/td_queue.c @@ -0,0 +1,248 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +static void checkGenTdQueue(void) +{ + UsbdEndpoint_t *queueStart_tmp1; + + if ( !memPool->m_freeHcTdList ) + { + return; + } + for ( queueStart_tmp1 = memPool->m_tdQueueStart; queueStart_tmp1 && queueStart_tmp1->m_inTdQueue != GENTD_QUEUE; + queueStart_tmp1 = queueStart_tmp1->m_busyNext ) + { + } + if ( queueStart_tmp1 ) + handleIoReqList(queueStart_tmp1); +} + +void processDoneQueue_GenTd(UsbdHcTD_t *arg) +{ + u32 tdHcArea; + const u8 *curBufPtr; + const void *bufferEnd; + UsbdIoRequest_t **lut_ptr1; + u32 hcRes; + UsbdIoRequest_t *req_1; + UsbdHcED_t *ed; + UsbdHcTD_t *tdListPos_2; + UsbdHcTD_t *nextTd; + UsbdIoRequest_t *req_2; + UsbdIoRequest_t *listPos; + UsbdIoRequest_t *pos; + UsbdIoRequest_t *next_tmp1; + UsbdIoRequest_t *firstElem; + UsbdIoRequest_t *lastElem; + + lastElem = NULL; + firstElem = NULL; + tdHcArea = arg->m_hcArea; + curBufPtr = (u8 *)arg->m_curBufPtr; + bufferEnd = arg->m_bufferEnd; + lut_ptr1 = &memPool->m_hcTdToIoReqLUT[arg - memPool->m_hcTdBuf]; + hcRes = tdHcArea >> 28; + req_1 = *lut_ptr1; + *lut_ptr1 = NULL; + if ( !req_1 ) + { + return; + } + freeTd(arg); + if ( bufferEnd && ((tdHcArea & 0x180000) != 0) ) // dir != SETUP + { + // transfer successful when !curBufPtr + req_1->m_transferedBytes = curBufPtr ? (u32)(curBufPtr - (u8 *)req_1->m_destPtr) : req_1->m_length; + } + if ( req_1->m_resultCode == USB_RC_OK ) + req_1->m_resultCode = hcRes; + if ( hcRes || ((tdHcArea & 0xE00000) != 0xE00000) ) // E00000: interrupts disabled + { + req_1->m_prev = NULL; + firstElem = req_1; + req_1->m_next = NULL; + lastElem = req_1; + } + ed = req_1->m_correspEndpoint->m_hcEd; + if ( hcRes && ED_HALTED(*ed) ) + { + for ( tdListPos_2 = (UsbdHcTD_t *)((uiptr)ed->m_tdHead & ~0xF); tdListPos_2 && tdListPos_2 != ed->m_tdTail; + tdListPos_2 = nextTd ) + { + UsbdIoRequest_t **lut_ptr2; + + nextTd = tdListPos_2->m_next; + freeTd(tdListPos_2); + lut_ptr2 = &memPool->m_hcTdToIoReqLUT[tdListPos_2 - memPool->m_hcTdBuf]; + req_2 = *lut_ptr2; + *lut_ptr2 = NULL; + if ( !req_2 ) + { + continue; + } + for ( listPos = firstElem; listPos && listPos != req_2; listPos = listPos->m_next ) + { + } + if ( listPos ) + { + continue; + } + req_2->m_resultCode = USB_RC_ABORTED; + req_2->m_prev = lastElem; + if ( lastElem ) + lastElem->m_next = req_2; + else + firstElem = req_2; + req_2->m_next = NULL; + lastElem = req_2; + } + ed->m_tdHead = ed->m_tdTail; + } + for ( pos = firstElem; pos; pos = next_tmp1 ) + { + pos->m_busyFlag = 0; + next_tmp1 = pos->m_next; + if ( pos->m_correspEndpoint->m_correspDevice ) + { + if ( pos->m_callbackProc ) + pos->m_callbackProc(pos); + } + else + { + freeIoRequest(pos); + } + } + checkGenTdQueue(); +} + +static void checkIsoTdQueue(void) +{ + UsbdEndpoint_t *queueStart_tmp1; + + if ( !memPool->m_freeHcIsoTdList ) + { + return; + } + for ( queueStart_tmp1 = memPool->m_tdQueueStart; queueStart_tmp1 && queueStart_tmp1->m_inTdQueue != ISOTD_QUEUE; + queueStart_tmp1 = queueStart_tmp1->m_busyNext ) + { + } + if ( queueStart_tmp1 ) + handleIoReqList(queueStart_tmp1); +} + +void processDoneQueue_IsoTd(UsbdHcIsoTD_t *arg) +{ + u32 hcArea; + unsigned int psw_tmp; + u32 tdHcRes; + unsigned int pswRes; + UsbdIoRequest_t **lut_ptr1; + int pswOfs; + UsbdIoRequest_t *req_1; + UsbdHcED_t *ed; + UsbdHcTD_t *tdHead; + UsbdHcIsoTD_t *curTd; + UsbdHcIsoTD_t *nextTd; + UsbdIoRequest_t *req_2; + UsbdIoRequest_t *listPos; + UsbdIoRequest_t *pos; + UsbdIoRequest_t *next_tmp1; + UsbdIoRequest_t *listStart; + UsbdIoRequest_t *listEnd; + + hcArea = arg->m_hcArea; + psw_tmp = arg->m_psw[0]; + tdHcRes = hcArea >> 28; + pswRes = psw_tmp >> 12; + lut_ptr1 = &memPool->m_hcIsoTdToIoReqLUT[arg - memPool->m_hcIsoTdBuf]; + pswOfs = psw_tmp & 0x7FF; + req_1 = *lut_ptr1; + *lut_ptr1 = NULL; + if ( !req_1 ) + { + return; + } + if ( req_1->m_req.bNumPackets ) + bcopy(arg->m_psw, req_1->m_req.Packets, 16); + freeIsoTd(arg); + req_1->m_transferedBytes = 0; + if ( req_1->m_req.bNumPackets ) + { + req_1->m_resultCode = tdHcRes; + } + else + { + req_1->m_resultCode = tdHcRes | (pswRes << 4); + if ( tdHcRes == USB_RC_OK && (pswRes == USB_RC_OK || pswRes == USB_RC_DATAUNDER) ) + { + if ( (req_1->m_correspEndpoint->m_hcEd->m_hcArea.stru.m_hcArea & HCED_DIR_MASK) == HCED_DIR_IN ) + req_1->m_transferedBytes = pswOfs; + else + req_1->m_transferedBytes = req_1->m_length; + } + } + req_1->m_prev = NULL; + listStart = req_1; + req_1->m_next = NULL; + listEnd = req_1; + ed = req_1->m_correspEndpoint->m_hcEd; + tdHead = ed->m_tdHead; + if ( ED_HALTED(*ed) ) + { + for ( curTd = (UsbdHcIsoTD_t *)((uiptr)tdHead & ~0xF); curTd && curTd != (UsbdHcIsoTD_t *)(ed->m_tdTail); + curTd = nextTd ) + { + UsbdIoRequest_t **lut_ptr2; + + nextTd = curTd->m_next; + freeIsoTd(curTd); + lut_ptr2 = &memPool->m_hcIsoTdToIoReqLUT[curTd - memPool->m_hcIsoTdBuf]; + req_2 = *lut_ptr2; + *lut_ptr2 = NULL; + if ( req_2 ) + { + for ( listPos = listStart; listPos && listPos != req_2; listPos = listPos->m_next ) + { + } + if ( listPos ) + { + continue; + } + req_2->m_resultCode = USB_RC_ABORTED; + req_2->m_prev = listEnd; + if ( listEnd ) + listEnd->m_next = req_2; + else + listStart = req_2; + req_2->m_next = NULL; + listEnd = req_2; + } + } + ed->m_tdHead = ed->m_tdTail; + } + for ( pos = listStart; pos; pos = next_tmp1 ) + { + pos->m_busyFlag = 0; + next_tmp1 = pos->m_next; + if ( pos->m_correspEndpoint->m_correspDevice ) + { + if ( pos->m_callbackProc ) + pos->m_callbackProc(pos); + } + else + { + freeIoRequest(pos); + } + } + checkIsoTdQueue(); +} diff --git a/iop/usb/usbd/src/timer.c b/iop/usb/usbd/src/timer.c new file mode 100644 index 00000000000..4e176bc63d8 --- /dev/null +++ b/iop/usb/usbd/src/timer.c @@ -0,0 +1,103 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +int addTimerCallback(UsbdTimerCbStruct_t *arg, TimerCallback func, void *cbArg, int delay) +{ + UsbdTimerCbStruct_t *pos; + + if ( arg->m_isActive ) + return -1; + arg->m_isActive = 1; + if ( delay > 0 ) + delay -= 1; + arg->m_callbackProc = func; + arg->m_callbackArg = cbArg; + for ( pos = memPool->m_timerListStart; pos && delay >= (int)pos->m_delayCount; + delay -= pos->m_delayCount, pos = pos->m_prev ) + { + } + if ( pos ) + { + arg->m_next = pos->m_next; + if ( pos->m_next ) + pos->m_next->m_prev = arg; + else + memPool->m_timerListStart = arg; + arg->m_prev = pos; + pos->m_next = arg; + pos->m_delayCount -= delay; + } + else + { + arg->m_next = memPool->m_timerListEnd; + if ( memPool->m_timerListEnd ) + memPool->m_timerListEnd->m_prev = arg; + else + memPool->m_timerListStart = arg; + memPool->m_timerListEnd = arg; + arg->m_prev = NULL; + } + arg->m_delayCount = delay; + memPool->m_ohciRegs->HcInterruptEnable = OHCI_INT_SF; + return 0; +} + +int cancelTimerCallback(UsbdTimerCbStruct_t *arg) +{ + if ( !arg->m_isActive ) + { + return -1; + } + if ( arg->m_prev ) + arg->m_prev->m_next = arg->m_next; + else + memPool->m_timerListEnd = arg->m_next; + if ( arg->m_next ) + arg->m_next->m_prev = arg->m_prev; + else + memPool->m_timerListStart = arg->m_prev; + arg->m_isActive = 0; + arg->m_next = NULL; + arg->m_prev = NULL; + return 0; +} + +void handleTimerList(void) +{ + UsbdTimerCbStruct_t *timer; + + timer = memPool->m_timerListStart; + if ( timer ) + { + if ( timer->m_delayCount > 0 ) + timer->m_delayCount -= 1; + while ( 1 ) + { + timer = memPool->m_timerListStart; + if ( !timer || (int)timer->m_delayCount > 0 ) + break; + dbg_printf("timer expired\n"); + memPool->m_timerListStart = timer->m_prev; + if ( timer->m_prev ) + timer->m_prev->m_next = NULL; + else + memPool->m_timerListEnd = NULL; + timer->m_next = NULL; + timer->m_prev = NULL; + timer->m_isActive = 0; + timer->m_callbackProc(timer->m_callbackArg); + } + } + // disable SOF interrupts if there are no timers left + if ( !memPool->m_timerListStart ) + memPool->m_ohciRegs->HcInterruptDisable = OHCI_INT_SF; +} diff --git a/iop/usb/usbd/src/usbd.c b/iop/usb/usbd/src/usbd.c deleted file mode 100644 index 0ce3cfd6ff6..00000000000 --- a/iop/usb/usbd/src/usbd.c +++ /dev/null @@ -1,410 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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 "mem.h" -#include "hcd.h" -#include "hub.h" -#include "usbio.h" - -#include "stdio.h" -#include "sysclib.h" -#include "thsemap.h" -#include "loadcore.h" -IRX_ID(MODNAME, 1, 1); - -#define WELCOME_STR "FreeUsbd v.0.1.2\n" - -// While the header of the export table is small, the large size of the export table (as a whole) places it in data instead of sdata. -extern struct irx_export_table _exp_usbd __attribute__((section("data"))); - -#ifndef MINI_DRIVER -UsbdConfig usbConfig = { - 0x20, // maxDevices - 0x40, // maxEndpoints - 0x80, // maxTransDesc - 0x80, // maxIsoTransfDesc - 0x100, // maxIoReqs - 0x200, // maxStaticDescSize - 8, // maxHubDevices - 8, // maxPortsPerHub - - 0x1E, // hcdThreadPrio - 0x24 // cbThreadPrio -}; -#else -UsbdConfig usbConfig = { - 0x10, // maxDevices - 0x20, // maxEndpoints - 0x40, // maxTransDesc - 0x40, // maxIsoTransfDesc - 0x100, // maxIoReqs - 0x200, // maxStaticDescSize - 4, // maxHubDevices - 4, // maxPortsPerHub - - 0x1E, // hcdThreadPrio - 0x24 // cbThreadPrio -}; -#endif - -int usbdSema; - -int usbdLock(void) -{ - return WaitSema(usbdSema); -} - -int usbdUnlock(void) -{ - return SignalSema(usbdSema); -} - -int doGetDeviceLocation(Device *dev, u8 *path) -{ - u8 tempPath[6]; - int count; - for (count = 0; (count < 6) && (dev != memPool.deviceTreeRoot); count++) { - tempPath[count] = dev->attachedToPortNo; - dev = dev->parent; - } - if (dev == memPool.deviceTreeRoot) { - int cpCount; - - for (cpCount = 0; cpCount < 7; cpCount++) { - if (cpCount < count) - path[cpCount] = tempPath[count - (cpCount + 1)]; - else - path[cpCount] = 0; - } - return 0; - } else - return USB_RC_BADHUBDEPTH; -} - -void processDoneQueue_IsoTd(HcIsoTD *arg) -{ - u32 tdHcRes = arg->hcArea >> 28; - u32 pswRes = arg->psw[0] >> 12; - u32 pswOfs = arg->psw[0] & 0x7FF; - - IoRequest *listStart = NULL, *listEnd = NULL; - - IoRequest *req = memPool.hcIsoTdToIoReqLUT[arg - memPool.hcIsoTdBuf]; - if (!req) - return; - - memPool.hcIsoTdToIoReqLUT[arg - memPool.hcIsoTdBuf] = NULL; - freeIsoTd(arg); - req->transferedBytes = 0; - req->resultCode = (pswRes << 4) | tdHcRes; - - if ((tdHcRes == USB_RC_OK) && ((pswRes == USB_RC_OK) || (pswRes == USB_RC_DATAUNDER))) { - if ((req->correspEndpoint->hcEd.hcArea & HCED_DIR_MASK) == HCED_DIR_IN) - req->transferedBytes = pswOfs; - else - req->transferedBytes = req->length; - } - - req->prev = listEnd; - if (listEnd) - listEnd->next = req; - else - listStart = req; - req->next = NULL; - listEnd = req; - - HcED *ed = &req->correspEndpoint->hcEd; - if (ED_HALTED(req->correspEndpoint->hcEd)) { - HcIsoTD *curTd = (HcIsoTD *)((u32)ed->tdHead & ~0xF); - - while (curTd && (curTd != (HcIsoTD *)ed->tdTail)) { - HcIsoTD *nextTd = curTd->next; - freeIsoTd(curTd); - - req = memPool.hcIsoTdToIoReqLUT[curTd - memPool.hcIsoTdBuf]; - if (req) { - memPool.hcIsoTdToIoReqLUT[arg - memPool.hcIsoTdBuf] = NULL; - IoRequest *listPos; - for (listPos = listStart; listPos != NULL; listPos = listPos->next) - if (listPos == req) - break; - if (listPos == NULL) { - req->resultCode = USB_RC_ABORTED; - req->prev = listEnd; - if (listEnd) - listEnd->next = req; - else - listStart = req; - req->next = NULL; - listEnd = req; - } - } - curTd = nextTd; - } - ed->tdHead = ed->tdTail; - } - - IoRequest *listPos = listStart; - while (listPos) { - IoRequest *listNext = listPos->next; - listPos->busyFlag = 0; - if (listPos->correspEndpoint->correspDevice) { - if (listPos->callbackProc) - listPos->callbackProc(listPos); - } else - freeIoRequest(listPos); - listPos = listNext; - } - checkTdQueue(ISOTD_QUEUE); -} - -void processDoneQueue_GenTd(HcTD *arg) -{ - IoRequest *req; - IoRequest *firstElem = NULL, *lastElem = NULL; - - u32 hcRes; - - if ((req = memPool.hcTdToIoReqLUT[arg - memPool.hcTdBuf])) { - memPool.hcTdToIoReqLUT[arg - memPool.hcTdBuf] = NULL; - - u32 tdHcArea = arg->HcArea; - - if (arg->bufferEnd && (tdHcArea & 0x180000)) { // dir != SETUP - if (arg->curBufPtr == 0) // transfer successful - req->transferedBytes = req->length; - else - req->transferedBytes = (u8 *)arg->curBufPtr - (u8 *)req->destPtr; - } - hcRes = tdHcArea >> 28; - freeTd(arg); - - if (req->resultCode == USB_RC_OK) - req->resultCode = hcRes; - - if (hcRes || ((tdHcArea & 0xE00000) != 0xE00000)) { // E00000: interrupts disabled - req->prev = lastElem; -#if 0 - // lastElem is NULL, so this condition is always false - if (lastElem) - { - lastElem->next = req; - } - else -#endif - { - firstElem = req; - } - req->next = NULL; - lastElem = req; - } - - HcED *ed = &req->correspEndpoint->hcEd; - if (hcRes && ED_HALTED(req->correspEndpoint->hcEd)) { - HcTD *tdListPos = (HcTD *)((u32)ed->tdHead & ~0xF); - while (tdListPos && (tdListPos != ed->tdTail)) { - HcTD *nextTd = tdListPos->next; - freeTd(tdListPos); - - req = memPool.hcTdToIoReqLUT[tdListPos - memPool.hcTdBuf]; - if (req) { - memPool.hcTdToIoReqLUT[tdListPos - memPool.hcTdBuf] = NULL; - - IoRequest *listPos; - for (listPos = firstElem; listPos != NULL; listPos = listPos->next) - if (listPos == req) - break; - - if (!listPos) { - req->resultCode = USB_RC_ABORTED; - req->prev = lastElem; - if (lastElem) - lastElem->next = req; - else - firstElem = req; - req->next = NULL; - lastElem = req; - } - } - tdListPos = nextTd; - } - ed->tdHead = ed->tdTail; - } - - IoRequest *pos = firstElem; - while (pos) { - pos->busyFlag = 0; - Device *dev = pos->correspEndpoint->correspDevice; - IoRequest *next = pos->next; - if (dev) { - if (pos->callbackProc) - pos->callbackProc(pos); - } else - freeIoRequest(pos); - pos = next; - } - checkTdQueue(GENTD_QUEUE); - } -} - -void handleTimerList(void) -{ - TimerCbStruct *timer = memPool.timerListStart; - if (timer) { - if (timer->delayCount > 0) - timer->delayCount--; - - while (memPool.timerListStart && (memPool.timerListStart->delayCount == 0)) { - dbg_printf("timer expired\n"); - timer = memPool.timerListStart; - - memPool.timerListStart = timer->next; - if (timer->next) - timer->next->prev = NULL; - else - memPool.timerListEnd = NULL; - timer->next = timer->prev = NULL; - timer->isActive = 0; - timer->callbackProc(timer->callbackArg); - } - } - // disable SOF interrupts if there are no timers left - if (memPool.timerListStart == NULL) - memPool.ohciRegs->HcInterruptDisable = OHCI_INT_SF; -} - -struct ArgOption -{ - const char *param; - int *value, *value2; -}; - -static inline void ParseOptionInput(const struct ArgOption *option, const char *arguments) -{ - const char *p; - int value, NewValue; - - p = arguments; - value = 0; - while (*p != '\0') { - if (*p == ',') - break; - - if ((NewValue = *p - '0') > 9) { - return; - } else { - value = (((value << 2) + value) << 1) + NewValue; - p++; - } - } - - if ((option->value2 != NULL && *p == ',') || (option->value2 == NULL && *p != ',')) { - if (arguments < p++) { - *option->value = value; - } - - if (option->value2 != NULL) { - value = 0; - while (*p != '\0') { - if ((NewValue = *p - '0') > 9) { - return; - } else { - value = (((value << 2) + value) << 1) + NewValue; - p++; - } - } - - *option->value2 = value; - } - } -} - -int _start(int argc, char *argv[]) -{ - static const struct ArgOption SupportedArgs[] = { - {"dev=", - &usbConfig.maxDevices, - NULL}, - {"ed=", - &usbConfig.maxEndpoints, - NULL}, - {"gtd=", - &usbConfig.maxTransfDesc, - NULL}, - {"itd=", - &usbConfig.maxIsoTransfDesc, - NULL}, - {"ioreq=", - &usbConfig.maxIoReqs, - NULL}, - {"conf=", - &usbConfig.maxStaticDescSize, - NULL}, - {"hub=", - &usbConfig.maxHubDevices, - NULL}, - {"port=", - &usbConfig.maxPortsPerHub, - NULL}, - {"thpri=", - &usbConfig.hcdThreadPrio, - &usbConfig.cbThreadPrio}, - {NULL, - NULL, - NULL}}; - iop_sema_t sema; - const char *pArgs, *pParam; - int i, option; - - for (i = 1; i < argc; i++) { - for (option = 0; SupportedArgs[option].param != NULL; option++) { - pParam = SupportedArgs[option].param; - pArgs = argv[i]; - while (*pParam != '\0') { - if (*pArgs != *pParam) - break; - - pParam++; - pArgs++; - } - - if (*pParam == '\0') { - ParseOptionInput(&SupportedArgs[option], pArgs); - } - } - } - - - printf(WELCOME_STR); - - dbg_printf("library entries...\n"); - - if (RegisterLibraryEntries(&_exp_usbd) != 0) { - dbg_printf("RegisterLibraryEntries failed\n"); - return MODULE_NO_RESIDENT_END; - } - - sema.attr = 1; - sema.option = 0; - sema.initial = 1; - sema.max = 1; - usbdSema = CreateSema(&sema); - - hcdInit(); - - dbg_printf("Init done\n"); - return MODULE_RESIDENT_END; -} diff --git a/iop/usb/usbd/src/usbd_api.c b/iop/usb/usbd/src/usbd_api.c new file mode 100644 index 00000000000..c1732bc3855 --- /dev/null +++ b/iop/usb/usbd/src/usbd_api.c @@ -0,0 +1,640 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +int sceUsbdRegisterLdd(sceUsbdLddOps *driver) +{ + void *OldGP; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = doRegisterDriver(driver, OldGP); + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdRegisterAutoloader(sceUsbdLddOps *drv) +{ + void *OldGP; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = doRegisterAutoLoader(drv, OldGP); + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdUnregisterLdd(sceUsbdLddOps *driver) +{ + void *OldGP; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = doUnregisterDriver(driver); + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdUnregisterAutoloader(void) +{ + void *OldGP; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = doUnregisterAutoLoader(); + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +void *sceUsbdScanStaticDescriptor(int devId, void *data, u8 type) +{ + void *OldGP; + const UsbdDevice_t *dev; + void *res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = NULL; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + dev = fetchDeviceById(devId); + if ( dev && dev->m_deviceStatus == DEVICE_READY ) + res = doGetDeviceStaticDescriptor(devId, data, type); + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdGetDeviceLocation(int devId, u8 *path) +{ + void *OldGP; + int res; + UsbdDevice_t *dev; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = USB_RC_BADDEV; + dev = fetchDeviceById(devId); + if ( dev && dev->m_deviceStatus == DEVICE_READY ) + res = doGetDeviceLocation(dev, path); + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdSetPrivateData(int devId, void *data) +{ + void *OldGP; + int res; + UsbdDevice_t *dev; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = USB_RC_BADDEV; + dev = fetchDeviceById(devId); + if ( dev ) + { + dev->m_privDataField = data; + res = USB_RC_OK; + } + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +void *sceUsbdGetPrivateData(int devId) +{ + void *OldGP; + void *res; + UsbdDevice_t *dev; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = NULL; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + dev = fetchDeviceById(devId); + if ( dev ) + res = dev->m_privDataField; + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdOpenPipe(int devId, UsbEndpointDescriptor *desc) +{ + void *OldGP; + UsbdDevice_t *dev; + int res; + const UsbdEndpoint_t *ep; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = -1; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + ep = NULL; + dev = fetchDeviceById(devId); + if ( dev ) + ep = doOpenEndpoint(dev, desc, 0); + if ( ep ) + res = ep->m_id; + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdOpenPipeAligned(int devId, UsbEndpointDescriptor *desc) +{ + void *OldGP; + UsbdDevice_t *dev; + int res; + const UsbdEndpoint_t *ep; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = -1; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + ep = NULL; + dev = fetchDeviceById(devId); + if ( dev ) + ep = doOpenEndpoint(dev, desc, 1u); + if ( ep ) + res = ep->m_id; + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdClosePipe(int id) +{ + void *OldGP; + UsbdEndpoint_t *ep; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = USB_RC_BADPIPE; + ep = fetchEndpointById(id); + if ( ep ) + res = doCloseEndpoint(ep); + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +static void signalCallbackThreadFunc(UsbdIoRequest_t *req) +{ + int state; + + CpuSuspendIntr(&state); + req->m_prev = cbListEnd; + if ( !cbListEnd ) + cbListStart = req; + else + cbListEnd->m_next = req; + req->m_next = NULL; + cbListEnd = req; + CpuResumeIntr(state); + SetEventFlag(usbKernelResources.m_callbackEvent, 1u); +} + +static int usbdTransferPipeImpl( + void *gp_val, + int id, + void *data, + u32 length, + UsbDeviceRequest *option, + void *callback, + void *cbArg, + sceUsbdMultiIsochronousRequest *request) +{ + int res; + UsbdEndpoint_t *ep; + int bNumPackets; + UsbdIoRequest_t *req; + + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { + return res; + } + res = USB_RC_OK; + ep = fetchEndpointById(id); + if ( !ep ) + { + dbg_printf("sceUsbdTransferPipe: UsbdEndpoint_t %d not found\n", id); + res = USB_RC_BADPIPE; + } + bNumPackets = 0; + if ( request && res == USB_RC_OK ) + { + bNumPackets = request->bNumPackets; + data = request->bBufStart; + } + if ( request && res == USB_RC_OK ) + { + if ( (unsigned int)(bNumPackets - 1) >= 8 || !data ) + { + res = USB_RC_BADLENGTH; + } + } + if ( (request || (data && (int)length > 0)) && res == USB_RC_OK ) + { + if ( ep->m_alignFlag && ((uiptr)data & 3) != 0 ) + { + res = USB_RC_BADALIGN; + } + } + if ( request && res == USB_RC_OK ) + { + if ( ep->m_endpointType != TYPE_ISOCHRON ) + { + res = USB_RC_BADPIPE; + } + } + if ( request && res == USB_RC_OK ) + { + int i_pkt; + + length = 0; + for ( i_pkt = 0; i_pkt < bNumPackets; i_pkt += 1 ) + { + if ( (ep->m_hcEd->m_hcArea.stru.m_maxPacketSize & 0x7FFu) < request->Packets[i_pkt].bLength ) + { + res = USB_RC_BADLENGTH; + break; + } + length += request->Packets[i_pkt].bLength; + if ( ep->m_alignFlag && (((((uiptr)data) & 0xFF) + (length & 0xFF)) & 3) != 0 ) + { + res = USB_RC_BADALIGN; + break; + } + } + } + if ( (request || (data && (int)length > 0)) && res == USB_RC_OK ) + { + if ( (((uiptr)data + length - 1) >> 12) - ((uiptr)data >> 12) >= 2 ) + { + res = USB_RC_BADLENGTH; + } + } + if ( (!request && (data && (int)length > 0)) && res == USB_RC_OK ) + { + switch ( ep->m_endpointType ) + { + case TYPE_CONTROL: + { + if ( ((uiptr)data & 3) != 0 && (option->requesttype & 0x80) == 0 ) + { + if ( (ep->m_hcEd->m_hcArea.stru.m_maxPacketSize & 0x7FF) == 64 && (int)length >= 63 ) + { + res = USB_RC_BADALIGN; + } + } + break; + } + case TYPE_ISOCHRON: + { + if ( (ep->m_hcEd->m_hcArea.stru.m_maxPacketSize & 0x7FFu) < length ) + { + res = USB_RC_BADLENGTH; + } + break; + } + default: + { + break; + } + } + } + if ( res == USB_RC_OK ) + { + req = allocIoRequest(); + if ( !req ) + { + dbg_printf("Ran out of IoReqs\n"); + res = USB_RC_IOREQ; + } + } + if ( res == USB_RC_OK ) + { + req->m_userCallbackArg = cbArg; + req->m_gpSeg = gp_val; + req->m_req.bNumPackets = 0; + req->m_userCallbackProc = callback; + switch ( ep->m_endpointType ) + { + case TYPE_ISOCHRON: + { + if ( request ) + { + req->m_waitFrames = request->bRelStartFrame; + memcpy(&(req->m_req), request, sizeof(sceUsbdMultiIsochronousRequest)); + } + else + { + req->m_waitFrames = (u32)option; + } + res = attachIoReqToEndpoint(ep, req, data, length, signalCallbackThreadFunc); + break; + } + case TYPE_CONTROL: + { + if ( !option ) + { + freeIoRequest(req); + res = USB_RC_BADOPTION; + } + if ( res == USB_RC_OK ) + { + if ( option->length != length ) + { + freeIoRequest(req); + res = USB_RC_BADLENGTH; + } + } + if ( res == USB_RC_OK ) + { + res = doControlTransfer( + ep, + req, + option->requesttype, + option->request, + option->value, + option->index, + option->length, + data, + signalCallbackThreadFunc); + } + break; + } + default: + { + res = attachIoReqToEndpoint(ep, req, data, length, signalCallbackThreadFunc); + break; + } + } + } + usbdUnlock(); + return res; +} + +int sceUsbdTransferPipe(int id, void *data, u32 len, void *option, sceUsbdDoneCallback callback, void *cbArg) +{ + void *OldGP; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = usbdTransferPipeImpl(OldGP, id, data, len, (UsbDeviceRequest *)option, callback, cbArg, NULL); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdMultiIsochronousTransfer( + int pipeId, sceUsbdMultiIsochronousRequest *request, sceUsbdMultiIsochronousDoneCallback callback, void *cbArg) +{ + void *OldGP; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = usbdTransferPipeImpl(OldGP, pipeId, NULL, 0, NULL, callback, cbArg, request); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdChangeThreadPriority(int prio1, int prio2) +{ + void *OldGP; + int res; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = 0; + if ( usbConfig.m_hcdThreadPrio != prio1 ) + { + usbConfig.m_hcdThreadPrio = prio1; + res = ChangeThreadPriority(usbKernelResources.m_hcdTid, prio1); + } + if ( res == 0 && usbConfig.m_cbThreadPrio != prio2 ) + { + usbConfig.m_cbThreadPrio = prio2; + res = ChangeThreadPriority(usbKernelResources.m_callbackTid, prio2); + } +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} + +int sceUsbdGetReportDescriptor(int devId, int cfgNum, int ifNum, void **desc, u32 *len) +{ + void *OldGP; + int res; + UsbdDevice_t *dev; + UsbdReportDescriptor_t *hidDescriptorStart; + +#if USE_GP_REGISTER + OldGP = SetModuleGP(); +#else + OldGP = NULL; +#endif + res = USB_RC_BADCONTEXT; + if ( usbdLock() ) + { +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; + } + res = USB_RC_BADDEV; + hidDescriptorStart = NULL; + dev = fetchDeviceById(devId); + if ( dev ) + { + res = USB_RC_UNKNOWN; + for ( hidDescriptorStart = dev->m_reportDescriptorStart; + hidDescriptorStart + && ((int)hidDescriptorStart->m_cfgNum != cfgNum || (int)hidDescriptorStart->m_ifNum != ifNum); + hidDescriptorStart = hidDescriptorStart->m_next ) + { + } + } + if ( hidDescriptorStart ) + { + res = USB_RC_OK; + if ( desc ) + *desc = hidDescriptorStart->m_data; + if ( len ) + *len = hidDescriptorStart->m_length; + } + usbdUnlock(); +#if USE_GP_REGISTER + SetGP(OldGP); +#endif + return res; +} diff --git a/iop/usb/usbd/src/usbd_main.c b/iop/usb/usbd/src/usbd_main.c new file mode 100644 index 00000000000..b511a5d0868 --- /dev/null +++ b/iop/usb/usbd/src/usbd_main.c @@ -0,0 +1,336 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +#ifdef _IOP +IRX_ID("USB_driver", 2, 4); +#endif +// Based on the module from SCE SDK 3.1.0. + +static int usbdModuleUnload(void); + +extern struct irx_export_table _exp_usbd; + +static UsbdArgOption_t SupportedArgs[] = { + {"dev=", &usbConfig.m_maxDevices, NULL}, + {"ed=", &usbConfig.m_maxEndpoints, NULL}, + {"gtd=", &usbConfig.m_maxTransfDesc, NULL}, + {"itd=", &usbConfig.m_maxIsoTransfDesc, NULL}, + {"ioreq=", &usbConfig.m_maxIoReqs, NULL}, + {"conf=", &usbConfig.m_maxStaticDescSize, NULL}, + {"hub=", &usbConfig.m_maxHubDevices, NULL}, + {"port=", &usbConfig.m_maxPortsPerHub, NULL}, + {"thpri=", &usbConfig.m_hcdThreadPrio, &usbConfig.m_cbThreadPrio}, + {"reportd=", &usbConfig.m_curDescNum, NULL}, + {NULL, NULL, NULL}}; + +UsbdMemoryPool_t *memPool = NULL; +UsbdKernelResources_t usbKernelResources = {-1, -1, -1, -1, -1}; +UsbdIoRequest_t *cbListStart = NULL; +UsbdIoRequest_t *cbListEnd = NULL; +#ifndef MINI_DRIVER +UsbdConfig_t usbConfig = { + 0x20, + 0x40, + 0x80, + 0x80, + 0x100, + 0x200, + 0x8, + 0x8, + 0x0, + 0x1E, + 0x24, + 0x0, +}; +#else +UsbdConfig_t usbConfig = { + 0x10, + 0x20, + 0x40, + 0x40, + 0x100, + 0x200, + 0x4, + 0x4, + 0x0, + 0x1E, + 0x24, + 0x0, +}; +#endif +sceUsbdLddOps *drvListStart = NULL; +sceUsbdLddOps *drvListEnd = NULL; +sceUsbdLddOps *drvAutoLoader = NULL; + +static int usbdIntrHandler(void *arg) +{ + const UsbdKernelResources_t *kernelResources; + + kernelResources = (UsbdKernelResources_t *)arg; + iSetEventFlag(kernelResources->m_hcdIrqEvent, 1u); + return 0; +} + +static void hcdIrqThread(void *arg) +{ + u32 efres; + + (void)arg; + while ( 1 ) + { + WaitEventFlag(usbKernelResources.m_hcdIrqEvent, 1u, WEF_OR | WEF_CLEAR, &efres); + usbdLock(); + hcdProcessIntr(); + EnableIntr(IOP_IRQ_USB); + PostIntrEnableFunction(); + usbdUnlock(); + } +} + +static void callbackThreadFunc(void *arg) +{ + UsbdIoRequest_t *req; + UsbdIoRequest_t reqCopy; + u32 efres; + int state; + + (void)arg; + while ( 1 ) + { + WaitEventFlag(usbKernelResources.m_callbackEvent, 1u, WEF_OR | WEF_CLEAR, &efres); + while ( 1 ) + { + CpuSuspendIntr(&state); + req = cbListStart; + if ( req ) + { + if ( req->m_next ) + req->m_next->m_prev = req->m_prev; + else + cbListEnd = req->m_prev; + if ( req->m_prev ) + req->m_prev->m_next = req->m_next; + else + cbListStart = req->m_next; + } + CpuResumeIntr(state); + if ( !req ) + break; + bcopy(req, &reqCopy, sizeof(UsbdIoRequest_t)); + usbdLock(); + freeIoRequest(req); + usbdUnlock(); + if ( reqCopy.m_userCallbackProc ) + { +#if USE_GP_REGISTER + SetGP(reqCopy.m_gpSeg); +#endif + if ( reqCopy.m_req.bNumPackets ) + reqCopy.m_userCallbackProcMultiIsochronous(reqCopy.m_resultCode, &reqCopy.m_req, reqCopy.m_userCallbackArg); + else + reqCopy.m_userCallbackProcRegular(reqCopy.m_resultCode, reqCopy.m_transferedBytes, reqCopy.m_userCallbackArg); +#if USE_GP_REGISTER + SetGP(_gp); +#endif + } + } + } +} + +void usbdReboot(int ac) +{ + if ( (unsigned int)ac < 2 ) + usbdRebootInner(); +} + +static void ParseOptionInput(const UsbdArgOption_t *option, const char *arguments) +{ + int value_1; + const char *p_1; + int value_2; + const char *p_2; + + value_1 = 0; + for ( p_1 = arguments; *p_1 && *p_1 != ','; p_1 += 1 ) + { + if ( (unsigned int)(*p_1 - '0') >= 9 ) + return; + value_1 = 10 * value_1 + (*p_1 - '0'); + } + if ( option->value2 ? (*p_1 != ',') : (*p_1 == ',') ) + return; + if ( arguments < p_1 ) + *option->value = value_1; + if ( !option->value2 ) + { + return; + } + value_2 = 0; + for ( p_2 = p_1 + 1; *p_2; p_2 += 1 ) + { + if ( (unsigned int)(*p_2 - '0') >= 9 ) + return; + value_2 = 10 * value_2 + (*p_2 - '0'); + } + if ( p_1 + 1 < p_2 ) + *option->value2 = value_2; +} + +int _start(int ac, char *av[], void *startaddr, ModuleInfo_t *mi) +{ + int i; + UsbdArgOption_t *args_ptr; + const char *pParam; + char *pArgs; + iop_event_t ef; + iop_thread_t thparam; + iop_sema_t sema; + int intrstate; + + (void)startaddr; + if ( ac < 0 ) + return usbdModuleUnload(); + for ( i = 1; i < ac; i += 1 ) + { + for ( args_ptr = SupportedArgs; args_ptr->param; args_ptr += 1 ) + { + int j; + for ( j = 0, pParam = args_ptr->param, pArgs = av[i]; pParam[j] && pParam[j] == pArgs[j]; j += 1 ) + { + } + if ( !pParam[j] ) + { + ParseOptionInput(args_ptr, pArgs); + break; + } + } + } + dbg_printf("Intr handler...\n"); + DisableIntr(IOP_IRQ_USB, &intrstate); + if ( RegisterIntrHandler(IOP_IRQ_USB, 1, usbdIntrHandler, &usbKernelResources) ) + { + if ( intrstate == IOP_IRQ_USB ) + { + EnableIntr(IOP_IRQ_USB); + return MODULE_NO_RESIDENT_END; + } + } + else + { + dbg_printf("library entries...\n"); + if ( !RegisterLibraryEntries(&_exp_usbd) ) + { + dbg_printf("Threads and events...\n"); + + sema.attr = SA_THPRI; + sema.initial = 1; + sema.max = 1; + sema.option = 0; + usbKernelResources.m_usbdSema = CreateSema(&sema); + if ( usbKernelResources.m_usbdSema >= 0 ) + { + ef.attr = EA_SINGLE; + ef.option = 0; + ef.bits = 0; + usbKernelResources.m_hcdIrqEvent = CreateEventFlag(&ef); + if ( usbKernelResources.m_hcdIrqEvent >= 0 ) + { + dbg_printf("HCD thread...\n"); + thparam.attr = TH_C; + thparam.thread = hcdIrqThread; +#ifndef MINI_DRIVER + thparam.stacksize = 0x4000; // 16KiB +#else + thparam.stacksize = 0x0800; // 2KiB +#endif + thparam.option = 0; + thparam.priority = usbConfig.m_hcdThreadPrio; + usbKernelResources.m_hcdTid = CreateThread(&thparam); + if ( usbKernelResources.m_hcdTid >= 0 && !StartThread(usbKernelResources.m_hcdTid, NULL) ) + { + ef.attr = EA_SINGLE; + ef.option = 0; + ef.bits = 0; + usbKernelResources.m_callbackEvent = CreateEventFlag(&ef); + if ( usbKernelResources.m_callbackEvent >= 0 ) + { + dbg_printf("Callback thread...\n"); + thparam.attr = TH_C; + thparam.thread = callbackThreadFunc; +#ifndef MINI_DRIVER + thparam.stacksize = 0x4000; // 16KiB +#else + thparam.stacksize = 0x0800; // 2KiB +#endif + thparam.option = 0; + thparam.priority = usbConfig.m_cbThreadPrio; + usbKernelResources.m_callbackTid = CreateThread(&thparam); + if ( + usbKernelResources.m_callbackTid >= 0 && !StartThread(usbKernelResources.m_callbackTid, NULL) + && usbdInitInner() >= 0 ) + { + dbg_printf("Enabling interrupts...\n"); + EnableIntr(IOP_IRQ_USB); + dbg_printf("Init done\n"); +#if 0 + return MODULE_REMOVABLE_END; +#else + if ( mi && ((mi->newflags & 2) != 0) ) + mi->newflags |= 0x10; + return MODULE_RESIDENT_END; +#endif + } + } + } + } + } + } + else + { + dbg_printf("RegisterLibraryEntries failed\n"); + } + if ( usbKernelResources.m_callbackTid > 0 ) + DeleteThread(usbKernelResources.m_callbackTid); + if ( usbKernelResources.m_callbackEvent > 0 ) + DeleteEventFlag(usbKernelResources.m_callbackEvent); + if ( usbKernelResources.m_hcdTid > 0 ) + DeleteThread(usbKernelResources.m_hcdTid); + if ( usbKernelResources.m_hcdIrqEvent > 0 ) + DeleteEventFlag(usbKernelResources.m_hcdIrqEvent); + if ( usbKernelResources.m_usbdSema > 0 ) + DeleteSema(usbKernelResources.m_usbdSema); + ReleaseIntrHandler(IOP_IRQ_USB); + } + return MODULE_NO_RESIDENT_END; +} + +static int usbdModuleUnload(void) +{ + int intrstate; + + if ( ReleaseLibraryEntries(&_exp_usbd) == 0 ) + { + return MODULE_REMOVABLE_END; + } + DisableIntr(IOP_IRQ_USB, &intrstate); + ReleaseIntrHandler(IOP_IRQ_USB); + TerminateThread(usbKernelResources.m_hcdTid); + TerminateThread(usbKernelResources.m_callbackTid); + DeleteThread(usbKernelResources.m_hcdTid); + DeleteThread(usbKernelResources.m_callbackTid); + DeleteEventFlag(usbKernelResources.m_hcdIrqEvent); + DeleteEventFlag(usbKernelResources.m_callbackEvent); + DeleteSema(usbKernelResources.m_usbdSema); + deinitHcd(); + deinitHubDriver(); + return MODULE_NO_RESIDENT_END; +} diff --git a/iop/usb/usbd/src/usbd_sys.c b/iop/usb/usbd/src/usbd_sys.c new file mode 100644 index 00000000000..c5fd7cff1dc --- /dev/null +++ b/iop/usb/usbd/src/usbd_sys.c @@ -0,0 +1,43 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "usbdpriv.h" + +void *AllocSysMemoryWrap(int size) +{ + void *ptr; + int state; + + CpuSuspendIntr(&state); + ptr = AllocSysMemory(ALLOC_FIRST, size, NULL); + CpuResumeIntr(state); + return ptr; +} + +int FreeSysMemoryWrap(void *ptr) +{ + int res; + int state; + + CpuSuspendIntr(&state); + res = FreeSysMemory(ptr); + CpuResumeIntr(state); + return res; +} + +int usbdLock(void) +{ + return WaitSema(usbKernelResources.m_usbdSema); +} + +int usbdUnlock(void) +{ + return SignalSema(usbKernelResources.m_usbdSema); +} diff --git a/iop/usb/usbd/src/usbdpriv.h b/iop/usb/usbd/src/usbdpriv.h index 457f0e516f5..3ed0c2af844 100644 --- a/iop/usb/usbd/src/usbdpriv.h +++ b/iop/usb/usbd/src/usbdpriv.h @@ -3,7 +3,7 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright ps2dev - http://www.ps2dev.org # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. */ @@ -16,37 +16,46 @@ #ifndef __USBDPRIV_H__ #define __USBDPRIV_H__ -#include "usbd.h" -#include "types.h" +#include "irx_imports.h" + #include "defs.h" +#include "types.h" +#include "usbd.h" #define OHCI_REG_BASE 0xBF801600 -#define MODNAME "usbd" #ifdef DEBUG -#define dbg_printf(a...) printf(MODNAME ": " a) +#define dbg_printf(a...) printf("usbd: " a) #else #define dbg_printf(a...) (void)0 #endif #define READ_UINT16(a) (((u8 *)a)[0] | (((u8 *)a)[1] << 8)) -typedef struct +typedef struct _argOption { - int maxDevices; - int maxEndpoints; - int maxTransfDesc; - int maxIsoTransfDesc; - int maxIoReqs; - int maxStaticDescSize; - int maxHubDevices; - int maxPortsPerHub; + const char *param; + int *value; + int *value2; +} UsbdArgOption_t; - int hcdThreadPrio; - int cbThreadPrio; -} UsbdConfig; - -extern UsbdConfig usbConfig; +typedef struct _usbdConfig +{ + int m_maxDevices; + int m_maxEndpoints; + int m_maxTransfDesc; + int m_maxIsoTransfDesc; + int m_maxIoReqs; + int m_maxStaticDescSize; + int m_maxHubDevices; + int m_maxPortsPerHub; + int m_allocatedSize_unused; + int m_hcdThreadPrio; + int m_cbThreadPrio; + int m_curDescNum; +} UsbdConfig_t; + +extern UsbdConfig_t usbConfig; struct _device; struct _ioRequest; @@ -62,268 +71,423 @@ typedef void (*InternCallback)(struct _ioRequest *arg); typedef struct _timerCbStruct { - u32 isActive; - struct _timerCbStruct *prev, *next; - TimerCallback callbackProc; - void *callbackArg; - u32 delayCount; -} TimerCbStruct; + u32 m_isActive; + struct _timerCbStruct *m_prev; + struct _timerCbStruct *m_next; + TimerCallback m_callbackProc; + void *m_callbackArg; + u32 m_delayCount; +} UsbdTimerCbStruct_t; typedef struct _ioRequest { - u32 busyFlag; - struct _ioRequest *next, *prev; - struct _endpoint *correspEndpoint; - UsbDeviceRequest devReq; - void *destPtr; - u32 length; // length of destPtr buffer - InternCallback callbackProc; - u32 resultCode; - u32 transferedBytes; - u32 waitFrames; // number of frames to wait for isochronous transfers - sceUsbdDoneCallback userCallbackProc; - void *userCallbackArg; -#if USE_GP_REGISTER - void *gpSeg; -#endif -} IoRequest; + u32 m_id; + u32 m_busyFlag; + struct _ioRequest *m_next; + struct _ioRequest *m_prev; + struct _endpoint *m_correspEndpoint; + UsbDeviceRequest m_devReq; + void *m_destPtr; + u32 m_length; // length of m_destPtr buffer + InternCallback m_callbackProc; + u32 m_resultCode; + u32 m_transferedBytes; + u32 m_waitFrames; // number of frames to wait for isochronous transfers + void *m_userCallbackArg; + union + { + void *m_userCallbackProc; + sceUsbdDoneCallback m_userCallbackProcRegular; + sceUsbdMultiIsochronousDoneCallback m_userCallbackProcMultiIsochronous; + }; + void *m_gpSeg; + sceUsbdMultiIsochronousRequest m_req; +} UsbdIoRequest_t; typedef struct _device { - u32 id; - struct _device *next, *prev; - struct _endpoint *endpointListStart, *endpointListEnd; - sceUsbdLddOps *devDriver; - u8 deviceStatus; - u8 functionAddress; - u8 isLowSpeedDevice; - u8 resetFlag; - struct _device *childListStart, *childListEnd; - struct _device *parent; - u32 attachedToPortNo; - void *privDataField; - TimerCbStruct timer; - IoRequest ioRequest; - u32 functionDelay; // is this necessary? - void *staticDeviceDescPtr; - void *staticDeviceDescEndPtr; - u32 fetchDescriptorCounter; -} Device; + u32 m_id; + struct _device *m_next; + struct _device *m_prev; + struct _endpoint *m_endpointListStart; + struct _endpoint *m_endpointListEnd; + sceUsbdLddOps *m_devDriver; + u8 m_deviceStatus; + u8 m_functionAddress; + u8 m_isLowSpeedDevice; + u8 m_resetFlag; + u32 m_magicPowerValue; + struct _device *m_childListStart; + struct _device *m_childListEnd; + struct _device *m_parent; + u32 m_attachedToPortNo; + void *m_privDataField; + UsbdTimerCbStruct_t m_timer; + UsbdIoRequest_t m_ioRequest; + u32 m_functionDelay; + void *m_staticDeviceDescPtr; + void *m_staticDeviceDescEndPtr; + u32 m_fetchDescriptorCounter; + struct _usbdReportDescriptor *m_reportDescriptorCurForFetch; + struct _usbdReportDescriptor *m_reportDescriptorStart; + struct _usbdReportDescriptor *m_reportDescriptorEnd; +} UsbdDevice_t; typedef struct _hcTd { - u32 HcArea; - void *curBufPtr; - struct _hcTd *next; - void *bufferEnd; -} HcTD; + u32 m_hcArea; + void *m_curBufPtr; + struct _hcTd *m_next; + void *m_bufferEnd; +} UsbdHcTD_t; typedef struct _hcIsoTd { - u32 hcArea; - void *bufferPage0; - struct _hcIsoTd *next; - void *bufferEnd; - u16 psw[8]; -} HcIsoTD; + u32 m_hcArea; + void *m_bufferPage0; + struct _hcIsoTd *m_next; + void *m_bufferEnd; + u16 m_psw[8]; +} UsbdHcIsoTD_t; + +struct _hcEdHcArea +{ + u16 m_hcArea; + u16 m_maxPacketSize; +}; + +union _hcEdHcAreaU +{ + struct _hcEdHcArea stru; + u32 asu32; +}; typedef struct _hcEd { - u16 hcArea; - u16 maxPacketSize; - HcTD *tdTail; - HcTD *tdHead; - struct _hcEd *next; -} HcED; + union _hcEdHcAreaU m_hcArea; + UsbdHcTD_t *m_tdTail; + UsbdHcTD_t *m_tdHead; + struct _hcEd *m_next; +} UsbdHcED_t; typedef struct _endpoint { - u32 id; - u8 endpointType; - u8 inTdQueue; - u8 alignFlag; - u8 pad; - struct _endpoint *next, *prev; - struct _endpoint *busyNext, *busyPrev; - Device *correspDevice; - IoRequest *ioReqListStart; - IoRequest *ioReqListEnd; - u32 isochronLastFrameNum; // 40 - TimerCbStruct timer; // sizeof(TimerCbStruct) => 24 bytes - HcED hcEd; // HcED has to be aligned to 0x10 bytes! -} Endpoint; + u32 m_id; + u32 m_inTdQueue; + struct _endpoint *m_next; + struct _endpoint *m_prev; + struct _endpoint *m_busyNext; + struct _endpoint *m_busyPrev; + UsbdDevice_t *m_correspDevice; + UsbdIoRequest_t *m_ioReqListStart; + UsbdIoRequest_t *m_ioReqListEnd; + UsbdHcED_t *m_hcEd; + u32 m_endpointType; + u32 m_isochronLastFrameNum; // 40 + UsbdTimerCbStruct_t m_timer; // sizeof(UsbdTimerCbStruct_t) => 24 bytes + u32 m_alignFlag; + u8 m_schedulingIndex; + u8 m_waitHigh; + u8 m_waitLow; + u8 m_packetSizeForScheduling; +} UsbdEndpoint_t; typedef struct _usbHub { - struct _usbHub *next; - Endpoint *controlEp, *statusChangeEp; - IoRequest controlIoReq, statusIoReq; - UsbHubDescriptor desc; - u32 numChildDevices; - u32 portCounter; - u32 hubStatusCounter; - u16 hubStatus; // - u16 hubStatusChange; // unite to u32 to make it match portStatusChange - u32 portStatusChange; - u8 statusChangeInfo[8]; // depends on number of ports -} UsbHub; - -typedef struct + struct _usbHub *m_next; + u32 m_pad1[1]; + u32 m_curAllocatedCount; + UsbdDevice_t *m_dev; + UsbdEndpoint_t *m_controlEp; + UsbdEndpoint_t *m_statusChangeEp; + UsbdIoRequest_t m_controlIoReq; + UsbdIoRequest_t m_statusIoReq; + u32 m_maxPower; + u32 m_isSelfPowered; + UsbHubDescriptor m_desc; + u32 m_pad2[6]; + u32 m_numChildDevices; + u32 m_portCounter; + u32 m_hubStatusCounter; + u16 m_hubStatus; + u16 m_hubStatusChange; // unite to u32 to make it match portStatusChange + u32 m_portStatusChange; + u8 m_statusChangeInfo[8]; // depends on number of ports + u32 m_pad3[6]; +} UsbdUsbHub_t; + +typedef struct _hcCA { - volatile HcED *InterruptTable[32]; - volatile u16 FrameNumber; - volatile u16 pad; - volatile HcTD *DoneHead; - volatile u8 reserved[116]; - volatile u32 pad2; // expand struct to 256 bytes for alignment + volatile UsbdHcED_t *InterruptTable[32]; + volatile u16 FrameNumber; + volatile u16 pad; + volatile UsbdHcTD_t *DoneHead; + volatile u8 reserved[116]; + volatile u32 pad2; // expand struct to 256 bytes for alignment } HcCA; -typedef struct +typedef struct _ohciRegs { - volatile u32 HcRevision; - volatile u32 HcControl; - volatile u32 HcCommandStatus; - volatile u32 HcInterruptStatus; - volatile u32 HcInterruptEnable; - volatile u32 HcInterruptDisable; - volatile HcCA *HcHCCA; - volatile HcED *HcPeriodCurrentEd; - volatile HcED *HcControlHeadEd; - volatile HcED *HcControlCurrentEd; - volatile HcED *HcBulkHeadEd; - volatile HcED *HcBulkCurrentEd; - volatile u32 HcDoneHead; - volatile u32 HcFmInterval; - volatile u32 HcFmRemaining; - volatile u32 HcFmNumber; - volatile u32 HcPeriodicStart; - volatile u32 HcLsThreshold; - volatile u32 HcRhDescriptorA; - volatile u32 HcRhDescriptorB; - volatile u32 HcRhStatus; - volatile u32 HcRhPortStatus[2]; + volatile u32 HcRevision; + volatile u32 HcControl; + volatile u32 HcCommandStatus; + volatile u32 HcInterruptStatus; + volatile u32 HcInterruptEnable; + volatile u32 HcInterruptDisable; + volatile HcCA *HcHCCA; + volatile UsbdHcED_t *HcPeriodCurrentEd; + volatile UsbdHcED_t *HcControlHeadEd; + volatile UsbdHcED_t *HcControlCurrentEd; + volatile UsbdHcED_t *HcBulkHeadEd; + volatile UsbdHcED_t *HcBulkCurrentEd; + volatile u32 HcDoneHead; + volatile u32 HcFmInterval; + volatile u32 HcFmRemaining; + volatile u32 HcFmNumber; + volatile u32 HcPeriodicStart; + volatile u32 HcLsThreshold; + volatile u32 HcRhDescriptorA; + volatile u32 HcRhDescriptorB; + volatile u32 HcRhStatus; + volatile u32 HcRhPortStatus[2]; } OhciRegs; typedef struct _memPool { - volatile OhciRegs *ohciRegs; - volatile HcCA *hcHCCA; + volatile OhciRegs *m_ohciRegs; + volatile HcCA *m_hcHCCA; - struct _hcEd *hcEdBuf; + struct _hcEd *m_hcEdBuf; - struct _hcTd *freeHcTdList; - struct _hcTd *hcTdBuf; - struct _hcTd *hcTdBufEnd; + struct _hcTd *m_freeHcTdList; + struct _hcTd *m_hcTdBuf; + struct _hcTd *m_hcTdBufEnd; - struct _hcIsoTd *freeHcIsoTdList; - struct _hcIsoTd *hcIsoTdBuf; - struct _hcIsoTd *hcIsoTdBufEnd; + struct _hcIsoTd *m_freeHcIsoTdList; + struct _hcIsoTd *m_hcIsoTdBuf; + struct _hcIsoTd *m_hcIsoTdBufEnd; - struct _ioRequest **hcTdToIoReqLUT; - struct _ioRequest **hcIsoTdToIoReqLUT; + struct _ioRequest **m_hcTdToIoReqLUT; + struct _ioRequest **m_hcIsoTdToIoReqLUT; - struct _ioRequest *ioReqBufPtr; - struct _ioRequest *freeIoReqList; - struct _ioRequest *freeIoReqListEnd; + struct _ioRequest *m_ioReqBufPtr; + struct _ioRequest *m_freeIoReqList; + struct _ioRequest *m_freeIoReqListEnd; - struct _device *deviceTreeBuf; - struct _device *freeDeviceListStart; - struct _device *freeDeviceListEnd; + struct _device *m_deviceTreeBuf; + struct _device *m_freeDeviceListStart; + struct _device *m_freeDeviceListEnd; - struct _endpoint *endpointBuf; - struct _endpoint *freeEpListStart; - struct _endpoint *freeEpListEnd; + struct _endpoint *m_endpointBuf; + struct _endpoint *m_freeEpListStart; + struct _endpoint *m_freeEpListEnd; - struct _endpoint *tdQueueStart[2], *tdQueueEnd[2]; + struct _endpoint *m_tdQueueStart; + struct _endpoint *m_tdQueueEnd; - struct _timerCbStruct *timerListStart; - struct _timerCbStruct *timerListEnd; + u32 m_interruptBandwidthSchedulingValues[32]; + u32 m_delayResets; + int m_interruptCounters[9]; - struct _device *deviceTreeRoot; + struct _timerCbStruct *m_timerListStart; + struct _timerCbStruct *m_timerListEnd; - u32 delayResets; -} MemoryPool; + struct _device *m_deviceTreeRoot; +} UsbdMemoryPool_t; +typedef struct _usbdReportDescriptor +{ + struct _usbdReportDescriptor *m_next; + struct _usbdReportDescriptor *m_prev; + u32 m_cfgNum; + u32 m_ifNum; + u32 m_length; + u8 m_data[]; +} UsbdReportDescriptor_t; + +typedef struct _usbdKernelResources +{ + int m_usbdSema; + int m_hcdTid; + int m_hcdIrqEvent; + int m_callbackTid; + int m_callbackEvent; +} UsbdKernelResources_t; + +#define NOTIN_QUEUE 0 #define GENTD_QUEUE 1 #define ISOTD_QUEUE 2 -#define TYPE_CONTROL 0x3F -#define TYPE_BULK 0x40 +#define TYPE_CONTROL 0x3F +#define TYPE_BULK 0x40 #define TYPE_ISOCHRON 0x41 -#define DEVICE_NOTCONNECTED 0 -#define DEVICE_CONNECTED 1 -#define DEVICE_RESETDELAYED 2 -#define DEVICE_RESETPENDING 3 -#define DEVICE_RESETCOMPLETE 4 -#define DEVICE_READY 5 - -#define PORT_CONNECTION 0 -#define PORT_ENABLE 1 -#define PORT_SUSPEND 2 +#define DEVICE_NOTCONNECTED 1 +#define DEVICE_CONNECTED 3 +#define DEVICE_RESETDELAYED 4 +#define DEVICE_RESETPENDING 5 +#define DEVICE_RESETCOMPLETE 6 +#define DEVICE_FETCHINGDESCRIPTOR 7 +#define DEVICE_READY 8 + +#define PORT_CONNECTION 0 +#define PORT_ENABLE 1 +#define PORT_SUSPEND 2 #define PORT_OVER_CURRENT 3 -#define PORT_RESET 4 -#define PORT_POWER 8 -#define PORT_LOW_SPEED 9 +#define PORT_RESET 4 +#define PORT_POWER 8 +#define PORT_LOW_SPEED 9 -#define C_HUB_LOCAL_POWER 0 +#define C_HUB_LOCAL_POWER 0 #define C_HUB_OVER_CURRENT 1 -#define C_PORT_CONNECTION 16 -#define C_PORT_ENABLE 17 -#define C_PORT_SUSPEND 18 +#define C_PORT_CONNECTION 16 +#define C_PORT_ENABLE 17 +#define C_PORT_SUSPEND 18 #define C_PORT_OVER_CURRENT 19 -#define C_PORT_RESET 20 +#define C_PORT_RESET 20 #define BIT(x) (((u32)1) << (x)) -#define C_PORT_FLAGS (BIT(C_PORT_CONNECTION) | BIT(C_PORT_ENABLE) | BIT(C_PORT_SUSPEND) | BIT(C_PORT_OVER_CURRENT) | BIT(C_PORT_RESET)) +#define C_PORT_FLAGS \ + (BIT(C_PORT_CONNECTION) | BIT(C_PORT_ENABLE) | BIT(C_PORT_SUSPEND) | BIT(C_PORT_OVER_CURRENT) | BIT(C_PORT_RESET)) -#define HCED_DIR_OUT BIT(11) // Direction field -#define HCED_DIR_IN BIT(12) // Direction field -#define HCED_SPEED BIT(13) // Speed bit -#define HCED_SKIP BIT(14) // sKip bit -#define HCED_ISOC BIT(15) // Format bit +#define HCED_DIR_OUT BIT(11) // Direction field +#define HCED_DIR_IN BIT(12) // Direction field +#define HCED_SPEED BIT(13) // Speed bit +#define HCED_SKIP BIT(14) // Skip bit +#define HCED_ISOC BIT(15) // Format bit #define HCED_DIR_MASK (HCED_DIR_OUT | HCED_DIR_IN) -#define ED_HALTED(a) ((u32)((a).tdHead) & 1) -#define ED_SKIPPED(a) ((u32)((a).hcArea) & HCED_SKIP) +#define ED_HALTED(a) ((u32)((a).m_tdHead) & 1) +#define ED_SKIPPED(a) ((u32)((a).m_hcArea.stru.m_hcArea) & HCED_SKIP) -#define TD_HCAREA(CC, T, DI, DP, R) (((CC) << 12) | ((T) << 8) | ((DI) << 5) | ((DP) << 3) | ((R) << 2)) +#define TD_HCAREA(CC, T, DI, DP, R) (u32)((((CC) << 12) | ((T) << 8) | ((DI) << 5) | ((DP) << 3) | ((R) << 2))) #define TD_SETUP 0 -#define TD_OUT 1 -#define TD_IN 2 - -#define OHCI_INT_SO BIT(0) -#define OHCI_INT_WDH BIT(1) -#define OHCI_INT_SF BIT(2) -#define OHCI_INT_RD BIT(3) -#define OHCI_INT_UE BIT(4) -#define OHCI_INT_FNO BIT(5) +#define TD_OUT 1 +#define TD_IN 2 + +#define OHCI_INT_SO BIT(0) +#define OHCI_INT_WDH BIT(1) +#define OHCI_INT_SF BIT(2) +#define OHCI_INT_RD BIT(3) +#define OHCI_INT_UE BIT(4) +#define OHCI_INT_FNO BIT(5) #define OHCI_INT_RHSC BIT(6) -#define OHCI_INT_OC BIT(30) -#define OHCI_INT_MIE BIT(31) +#define OHCI_INT_OC BIT(30) +#define OHCI_INT_MIE BIT(31) #define OHCI_COM_HCR BIT(0) #define OHCI_COM_CLF BIT(1) #define OHCI_COM_BLF BIT(2) -#define OHCI_CTR_PLE BIT(2) // Periodic List Enable -#define OHCI_CTR_IE BIT(3) // Isochronous Enable -#define OHCI_CTR_CLE BIT(4) // Control List Enable -#define OHCI_CTR_BLE BIT(5) // Bulk List Enable -#define OHCI_CTR_USB_RESET (0 << 6) -#define OHCI_CTR_USB_RESUME (1 << 6) +#define OHCI_CTR_CBSR (3 << 0) // Control / Bulk Service Ratio +#define OHCI_CTR_PLE BIT(2) // Periodic List Enable +#define OHCI_CTR_IE BIT(3) // Isochronous Enable +#define OHCI_CTR_CLE BIT(4) // Control List Enable +#define OHCI_CTR_BLE BIT(5) // Bulk List Enable +#define OHCI_CTR_USB_RESET (0 << 6) +#define OHCI_CTR_USB_RESUME (1 << 6) #define OHCI_CTR_USB_OPERATIONAL (2 << 6) -#define OHCI_CTR_USB_SUSPEND (3 << 6) - -int usbdLock(void); -int usbdUnlock(void); -int doGetDeviceLocation(Device *dev, u8 *path); -void processDoneQueue_IsoTd(HcIsoTD *arg); -void processDoneQueue_GenTd(HcTD *arg); -void handleTimerList(void); - - -#endif // __USBDPRIV_H__ +#define OHCI_CTR_USB_SUSPEND (3 << 6) + +// The following is defined in hub.c +extern void hubResetDevicePort(UsbdDevice_t *dev); +extern int initHubDriver(void); +extern void deinitHubDriver(void); + +// The following is defined in mem.c +extern UsbdDevice_t *fetchDeviceById(int devId); +extern UsbdEndpoint_t *fetchEndpointById(int id); +extern UsbdDevice_t *getDeviceTreeRoot(void); +extern UsbdDevice_t *attachChildDevice(UsbdDevice_t *parent, u32 portNum); +extern void freeDevice(UsbdDevice_t *dev); +extern UsbdIoRequest_t *allocIoRequest(void); +extern void freeIoRequest(UsbdIoRequest_t *req); +extern UsbdEndpoint_t *allocEndpointForDevice(UsbdDevice_t *dev, u32 align); +extern int cleanUpFunc(UsbdDevice_t *dev, UsbdEndpoint_t *ep); +extern UsbdHcTD_t *allocTd(void); +extern void freeTd(UsbdHcTD_t *argTd); +extern UsbdHcIsoTD_t *allocIsoTd(void); +extern void freeIsoTd(UsbdHcIsoTD_t *argTd); + +// The following is defined in timer.c +extern int addTimerCallback(UsbdTimerCbStruct_t *arg, TimerCallback func, void *cbArg, int delay); +extern int cancelTimerCallback(UsbdTimerCbStruct_t *arg); +extern void handleTimerList(void); + +// The following is defined in endpoint.c +extern UsbdEndpoint_t *openDeviceEndpoint(UsbdDevice_t *dev, const UsbEndpointDescriptor *endpDesc, u32 alignFlag); +extern int removeEndpointFromDevice(UsbdDevice_t *dev, UsbdEndpoint_t *ep); + +// The following is defined in io_request.c +extern void handleIoReqList(UsbdEndpoint_t *ep); + +// The following is defined in hub_resets.c +extern void usbdRebootInner(void); +extern void hubResetDevice(UsbdDevice_t *dev); +extern int checkDelayedResets(UsbdDevice_t *dev); +extern void handleRhsc(void); + +// The following is defined in td_queue.c +extern void processDoneQueue_GenTd(UsbdHcTD_t *arg); +extern void processDoneQueue_IsoTd(UsbdHcIsoTD_t *arg); + +// The following is defined in hcd.c +extern void hcdProcessIntr(void); +extern void PostIntrEnableFunction(void); +extern int initHcdStructs(void); +extern void deinitHcd(void); + +// The following is defined in usbd_sys.c +extern void *AllocSysMemoryWrap(int size); +extern int FreeSysMemoryWrap(void *ptr); +extern int usbdLock(void); +extern int usbdUnlock(void); + +// The following is defined in usbd_main.c +extern void usbdReboot(int ac); + +// The following is defined in report_descriptor_init.c +extern int +handleStaticDeviceDescriptor(UsbdDevice_t *dev, UsbDeviceDescriptor *devDescStart, UsbDeviceDescriptor *devDescEnd); + +// The following is defined in device_driver.c +extern int callUsbDriverFunc(int (*func)(int devId), int devId, void *gpSeg); +extern int doRegisterDriver(sceUsbdLddOps *drv, void *drvGpSeg); +extern int doRegisterAutoLoader(sceUsbdLddOps *drv, void *drvGpSeg); +extern int doUnregisterDriver(sceUsbdLddOps *drv); +extern int doUnregisterAutoLoader(void); + +// The following is defined in device.c +extern void *doGetDeviceStaticDescriptor(int devId, void *data, u8 type); +extern int doGetDeviceLocation(UsbdDevice_t *dev, u8 *path); +extern UsbdEndpoint_t *doOpenEndpoint(UsbdDevice_t *dev, const UsbEndpointDescriptor *endpDesc, u32 alignFlag); +extern int doCloseEndpoint(UsbdEndpoint_t *ep); +extern int attachIoReqToEndpoint(UsbdEndpoint_t *ep, UsbdIoRequest_t *req, void *destdata, u16 length, void *callback); +extern int doControlTransfer( + UsbdEndpoint_t *ep, + UsbdIoRequest_t *req, + u8 requestType, + u8 request, + u16 value, + u16 index, + u16 length, + void *destdata, + void *callback); +extern int hubTimedSetFuncAddress(UsbdDevice_t *dev); +extern void flushPort(UsbdDevice_t *dev); +extern int usbdInitInner(void); + +// The following is defined in usbd_main.c +extern UsbdMemoryPool_t *memPool; +extern UsbdKernelResources_t usbKernelResources; +extern UsbdIoRequest_t *cbListStart; +extern UsbdIoRequest_t *cbListEnd; +extern UsbdConfig_t usbConfig; +extern sceUsbdLddOps *drvListStart; +extern sceUsbdLddOps *drvListEnd; +extern sceUsbdLddOps *drvAutoLoader; + +#endif // __USBDPRIV_H__ diff --git a/iop/usb/usbd/src/usbio.c b/iop/usb/usbd/src/usbio.c deleted file mode 100644 index d46c7c73e26..00000000000 --- a/iop/usb/usbd/src/usbio.c +++ /dev/null @@ -1,319 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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 "mem.h" -#include "usbio.h" - -#include "stdio.h" - -void removeEndpointFromQueue(Endpoint *ep) -{ - if (!ep->inTdQueue) - return; - - if (ep->busyNext) - ep->busyNext->busyPrev = ep->busyPrev; - else - memPool.tdQueueEnd[ep->inTdQueue - 1] = ep->busyPrev; - - if (ep->busyPrev) - ep->busyPrev->busyNext = ep->busyNext; - else - memPool.tdQueueStart[ep->inTdQueue - 1] = ep->busyNext; - - ep->inTdQueue = 0; -} - -void enqueueEndpoint(Endpoint *ep, u32 listType) -{ - if (ep->inTdQueue) - return; - - ep->busyNext = NULL; - ep->busyPrev = memPool.tdQueueEnd[listType - 1]; - if (memPool.tdQueueEnd[listType - 1]) - memPool.tdQueueEnd[listType - 1]->busyNext = ep; - else - memPool.tdQueueStart[listType - 1] = ep; - memPool.tdQueueEnd[listType - 1] = ep; - - ep->inTdQueue = listType; -} - -void checkTdQueue(int type) -{ - if ((type == GENTD_QUEUE) && !memPool.freeHcTdList) - return; - else if ((type == ISOTD_QUEUE) && !memPool.freeHcIsoTdList) - return; - - if (memPool.tdQueueStart[type - 1]) - handleIoReqList(memPool.tdQueueStart[type - 1]); -} - -int setupControlTransfer(Endpoint *ep) -{ - HcTD *statusTd, *tailTd, *dataTd = NULL; - IoRequest *curIoReq = ep->ioReqListStart; - - if (ep->hcEd.tdTail && !ED_HALTED(ep->hcEd) && !ED_SKIPPED(ep->hcEd) && curIoReq) { - if (curIoReq->destPtr && curIoReq->length) { - dataTd = allocTd(); - if (!dataTd) { - enqueueEndpoint(ep, GENTD_QUEUE); - return 0; - } - } - statusTd = allocTd(); - tailTd = allocTd(); - - if (!statusTd || !tailTd) { - freeTd(statusTd); - freeTd(tailTd); - freeTd(dataTd); - - enqueueEndpoint(ep, GENTD_QUEUE); - return 0; - } - - if (curIoReq->next) - curIoReq->next->prev = curIoReq->prev; - else - ep->ioReqListEnd = curIoReq->prev; - - if (curIoReq->prev) - curIoReq->prev->next = curIoReq->next; - else - ep->ioReqListStart = curIoReq->next; - - // first stage: setup - ep->hcEd.tdTail->HcArea = TD_HCAREA(USB_RC_NOTACCESSED, 2, 7, TD_SETUP, 0) << 16; - ep->hcEd.tdTail->curBufPtr = &curIoReq->devReq; - ep->hcEd.tdTail->bufferEnd = ((u8 *)&curIoReq->devReq) + sizeof(UsbDeviceRequest) - 1; - - memPool.hcTdToIoReqLUT[ep->hcEd.tdTail - memPool.hcTdBuf] = curIoReq; - - // second stage: data - if (dataTd) { - ep->hcEd.tdTail->next = dataTd; - - if (curIoReq->devReq.requesttype & USB_DIR_IN) - dataTd->HcArea = TD_HCAREA(USB_RC_NOTACCESSED, 3, 7, TD_IN, 1) << 16; - else - dataTd->HcArea = TD_HCAREA(USB_RC_NOTACCESSED, 3, 7, TD_OUT, 1) << 16; - - dataTd->curBufPtr = curIoReq->destPtr; - dataTd->bufferEnd = (u8 *)curIoReq->destPtr + curIoReq->length - 1; - dataTd->next = statusTd; - - memPool.hcTdToIoReqLUT[dataTd - memPool.hcTdBuf] = curIoReq; - } else - ep->hcEd.tdTail->next = statusTd; - - // third stage: status - if (curIoReq->devReq.requesttype & USB_DIR_IN) - statusTd->HcArea = TD_HCAREA(USB_RC_NOTACCESSED, 3, 0, TD_OUT, 0) << 16; - else - statusTd->HcArea = TD_HCAREA(USB_RC_NOTACCESSED, 3, 0, TD_IN, 0) << 16; - - statusTd->curBufPtr = NULL; - statusTd->bufferEnd = NULL; - statusTd->next = tailTd; - memPool.hcTdToIoReqLUT[statusTd - memPool.hcTdBuf] = curIoReq; - - ep->hcEd.tdTail = tailTd; - - memPool.ohciRegs->HcCommandStatus |= OHCI_COM_CLF; // control list filled - - // remove endpoint from busy list if there are no IoRequests left - if (!ep->ioReqListStart) - removeEndpointFromQueue(ep); - return 1; - } else { - // endpoint error - removeEndpointFromQueue(ep); - return 0; - } -} - -int setupIsocronTransfer(Endpoint *ep) -{ - IoRequest *curIoReq = ep->ioReqListStart; - - HcED *ed = &ep->hcEd; - HcIsoTD *curTd = (HcIsoTD *)ed->tdTail; - HcIsoTD *newTd; - - u32 frameNo; - - if (ep->hcEd.tdTail && !ED_HALTED(ep->hcEd) && !ED_SKIPPED(ep->hcEd) && curIoReq) { - newTd = allocIsoTd(); - if (!newTd) { - enqueueEndpoint(ep, ISOTD_QUEUE); - return 0; - } - - if (curIoReq->next) - curIoReq->next->prev = curIoReq->prev; - else - ep->ioReqListEnd = curIoReq->prev; - - if (curIoReq->prev) - curIoReq->prev->next = curIoReq->next; - else - ep->ioReqListStart = curIoReq->next; - - if (ed->tdTail == (HcTD *)((u32)ed->tdHead & ~0xF)) - frameNo = memPool.hcHCCA->FrameNumber + 2; - else - frameNo = ep->isochronLastFrameNum; - - frameNo = (frameNo + curIoReq->waitFrames) & 0xFFFF; - - ep->isochronLastFrameNum = frameNo + 1; - - curTd->hcArea = (USB_RC_NOTACCESSED << 28) | frameNo; - curTd->bufferPage0 = (void *)((u32)curIoReq->destPtr & ~0xFFF); - curTd->next = newTd; - - if (curIoReq->destPtr && curIoReq->length) - curTd->bufferEnd = (u8 *)curIoReq->destPtr + curIoReq->length - 1; - else - curTd->bufferEnd = NULL; - - curTd->psw[0] = (USB_RC_NOTACCESSED << 12) | ((u32)curIoReq->destPtr & 0xFFF); - - memPool.hcIsoTdToIoReqLUT[curTd - memPool.hcIsoTdBuf] = curIoReq; - - ed->tdTail = (HcTD *)newTd; - - // remove endpoint from busy list if there are no IoRequests left - if (!ep->ioReqListStart) - removeEndpointFromQueue(ep); - return 1; - } else { - // endpoint error - removeEndpointFromQueue(ep); - return 0; - } -} - -int setupBulkTransfer(Endpoint *ep) -{ - IoRequest *curIoReq = ep->ioReqListStart; - - HcED *ed = &ep->hcEd; - HcTD *curTd = ed->tdTail; - HcTD *newTd; - - if (ep->hcEd.tdTail && !ED_HALTED(ep->hcEd) && !ED_SKIPPED(ep->hcEd) && curIoReq) { - newTd = allocTd(); - if (!newTd) { - enqueueEndpoint(ep, GENTD_QUEUE); - return 0; - } - - if (curIoReq->next) - curIoReq->next->prev = curIoReq->prev; - else - ep->ioReqListEnd = curIoReq->prev; - - if (curIoReq->prev) - curIoReq->prev->next = curIoReq->next; - else - ep->ioReqListStart = curIoReq->next; - - curTd->HcArea = TD_HCAREA(USB_RC_NOTACCESSED, 0, 0, 3, 1) << 16; - curTd->next = newTd; - curTd->curBufPtr = curIoReq->destPtr; - - if (curIoReq->destPtr && curIoReq->length) - curTd->bufferEnd = (u8 *)curIoReq->destPtr + curIoReq->length - 1; - else - curTd->bufferEnd = NULL; - - memPool.hcTdToIoReqLUT[curTd - memPool.hcTdBuf] = curIoReq; - - ed->tdTail = newTd; - - if (ep->endpointType == TYPE_BULK) - memPool.ohciRegs->HcCommandStatus |= OHCI_COM_BLF; // Bulk List Filled - - // remove endpoint from busy list if there are no IoRequests left - if (!ep->ioReqListStart) - removeEndpointFromQueue(ep); - return 1; - } else { - // endpoint error - dbg_printf("ERROR Endpoint error\n"); - removeEndpointFromQueue(ep); - return 0; - } -} - -void handleIoReqList(Endpoint *ep) -{ - if (ep->endpointType == TYPE_CONTROL) - setupControlTransfer(ep); - else if (ep->endpointType == TYPE_ISOCHRON) - setupIsocronTransfer(ep); - else // bulk or interrupt - setupBulkTransfer(ep); -} - -int attachIoReqToEndpoint(Endpoint *ep, IoRequest *req, void *destdata, u16 length, void *callback) -{ - if (!ep->correspDevice) - return USB_RC_BUSY; - if (req->busyFlag) - return USB_RC_BUSY; - - req->busyFlag = 1; - req->correspEndpoint = ep; - req->destPtr = destdata; - req->length = length; - req->resultCode = 0; - req->transferedBytes = 0; - req->callbackProc = callback; - - req->next = NULL; - req->prev = ep->ioReqListEnd; - if (ep->ioReqListEnd) - ep->ioReqListEnd->next = req; - else - ep->ioReqListStart = req; - ep->ioReqListEnd = req; - - handleIoReqList(ep); - return 0; -} - -int doControlTransfer(Endpoint *ep, IoRequest *req, - u8 requestType, u8 request, u16 value, u16 index, u16 length, - void *destdata, void *callback) -{ - if (req->busyFlag) { - dbg_printf("ERROR: doControlTransfer: IoReq busy\n"); - return USB_RC_BUSY; - } - - req->devReq.requesttype = requestType; - req->devReq.request = request; - req->devReq.value = value; - req->devReq.index = index; - req->devReq.length = length; - return attachIoReqToEndpoint(ep, req, destdata, length, callback); -} diff --git a/iop/usb/usbd/src/usbio.h b/iop/usb/usbd/src/usbio.h deleted file mode 100644 index f767f35607c..00000000000 --- a/iop/usb/usbd/src/usbio.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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 __USBIO_H__ -#define __USBIO_H__ - -void removeEndpointFromQueue(Endpoint *ep); -void checkTdQueue(int type); -void handleIoReqList(Endpoint *ep); -int doControlTransfer(Endpoint *ep, IoRequest *req, - u8 requestType, u8 request, u16 value, u16 index, u16 length, - void *destdata, void *callback); -int attachIoReqToEndpoint(Endpoint *ep, IoRequest *req, void *destdata, u16 length, void *callback); -void handleIoReqList(Endpoint *ep); - -#endif // __USBIO_H__