usbloadergx/tinyehci/usb.c
dimok321 e510233154 *Added new ehcmodules with better and more drives support on Hermes IOS (thx rodries)
*Fixed reset of the loader when loading game with IOS reload and disabled WiiTDB titles (Issue 1874)
*Added new 'Inherit' or 'Use global' setting for game settings. If that option is set than the global setting is used for that option. (Issue 1842)
*Fixed timeout timer on startup to count correctly. (Issue 1907)
*Added two new video modes to force progressive video mode, 'FORCE PAL480p' and 'FORCE NTSC480p' (basically the same but oh well) (Issue 1902)
*Added the new 'Return to' procedure for the d2x v4 IOS for Test purpose (didn't test it, need feedback on this one). The old method is used if this procedure fails. Please test it on problematic games (e.g. PoP). (Issue 1892)
2011-05-28 19:52:00 +00:00

266 lines
7.1 KiB
C

/*
This file implements libogc usb API, but with ehci direct call
most of the file credit goes to libogc devs
*/
#define __usb_control_message(fd, b, c,d, e, f, g, h, i) ehci_control_message(fd,b,c,d,e,f,g)
static s32 __usb_getdesc(struct ehci_device * fd, u8 *buffer, u8 type, u8 index, u8 size)
{
printk("usb_get desc %X %X %p\n",type,index,buffer);
return __usb_control_message(fd, USB_ENDPOINT_IN ,USB_REQ_GETDESCRIPTOR, (type << 8) | index, 0, size, buffer, NULL, NULL);
}
static u32 __find_next_endpoint(u8 *buffer,u32 size)
{
u8 *ptr = buffer;
while(size>0) {
if(buffer[1]==USB_DT_ENDPOINT || buffer[1]==USB_DT_INTERFACE) break;
size -= buffer[0];
buffer += buffer[0];
}
return (buffer - ptr);
}
s32 USB_GetDescriptors(struct ehci_device * fd, usb_devdesc *udd)
{
u8 *buffer = NULL;
u8 *ptr = NULL;
usb_configurationdesc *ucd = NULL;
usb_interfacedesc *uid = NULL;
usb_endpointdesc *ued = NULL;
s32 retval = 0;
u32 size,i;
u32 iConf, iInterface, iEndpoint;
buffer = USB_Alloc(sizeof(*udd));
if(buffer == NULL)
{
s_printf("buffer == NULL (no mem)\n");
retval = -ENOMEM;
goto free_and_error;
}
ehci_msleep(10);
retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, USB_DT_DEVICE_SIZE);
if(retval < 0)
{
u32 status;
int ret;
s_printf("__usb_getdesc error USB_DT_DEVICE: retry\n");
ret=ehci_reset_port(current_port);
ehci_msleep(20);
status=ehci_readl(&ehci->regs->port_status[current_port]);
if(ret<0 || (status & 0x3105)!=0x1005)
{
ret=ehci_reset_port2(current_port);
ehci_msleep(20);
ehci_readl(&ehci->regs->port_status[current_port]);
}
ehci_msleep(30);
retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, USB_DT_DEVICE_SIZE);
if(retval < 0)
{
s_printf("__usb_getdesc error USB_DT_DEVICE\n");
goto free_and_error;
}
}
memcpy(udd, buffer, USB_DT_DEVICE_SIZE);
USB_Free(buffer);
udd->bcdUSB = cpu_to_le16(udd->bcdUSB);
udd->idVendor = cpu_to_le16(udd->idVendor);
udd->idProduct = cpu_to_le16(udd->idProduct);
udd->bcdDevice = cpu_to_le16(udd->bcdDevice);
udd->configurations = USB_Alloc(udd->bNumConfigurations* sizeof(*udd->configurations));
if(udd->configurations == NULL)
{
s_printf("udd->configurations == NULL (no mem)\n");
retval = -ENOMEM;
goto free_and_error;
}
memset(udd->configurations,0,udd->bNumConfigurations* sizeof(*udd->configurations));
for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
{
buffer = USB_Alloc( USB_DT_CONFIG_SIZE);
if(buffer == NULL)
{
s_printf("buffer == NULL (no mem)\n");
retval = -ENOMEM;
goto free_and_error;
}
retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, USB_DT_CONFIG_SIZE);
ucd = &udd->configurations[iConf];
memcpy(ucd, buffer, USB_DT_CONFIG_SIZE);
USB_Free( buffer);
ucd->wTotalLength = cpu_to_le16(ucd->wTotalLength);
size = ucd->wTotalLength;
buffer = USB_Alloc( ucd->wTotalLength);
if(buffer == NULL)
{
s_printf("buffer == NULL (no mem)\n");
retval = -ENOMEM;
goto free_and_error;
}
retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, ucd->wTotalLength);
if(retval < 0)
{
s_printf("__usb_getdesc error USB_DT_CONFIG: retry\n");
goto free_and_error;
}
ptr = buffer;
ptr += ucd->bLength;
size -= ucd->bLength;
retval = -ENOMEM;
ucd->interfaces = USB_Alloc(ucd->bNumInterfaces* sizeof(*ucd->interfaces));
if(ucd->interfaces == NULL)
{
s_printf("ucd->interfaces == NULL (no mem)\n");
goto free_and_error;
}
memset(ucd->interfaces,0,ucd->bNumInterfaces* sizeof(*ucd->interfaces));
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
{
uid = &ucd->interfaces[iInterface];
memcpy(uid, ptr, USB_DT_INTERFACE_SIZE);
ptr += uid->bLength;
size -= uid->bLength;
uid->endpoints = USB_Alloc(uid->bNumEndpoints* sizeof(*uid->endpoints));
if(uid->endpoints == NULL)
{
s_printf("uid->endpoints == NULL (no mem)\n");
goto free_and_error;
}
memset(uid->endpoints,0,uid->bNumEndpoints* sizeof(*uid->endpoints));
// This skips vendor and class specific descriptors
i = __find_next_endpoint(ptr, size);
uid->extra_size = i;
if(i>0)
{
uid->extra = USB_Alloc(i);
if(uid->extra == NULL)
{
s_printf("uid->extra == NULL (no mem)\n");
goto free_and_error;
}
memcpy(uid->extra, ptr, i);
ptr += i;
size -= i;
}
for(iEndpoint = 0; iEndpoint < uid->bNumEndpoints; iEndpoint++)
{
ued = &uid->endpoints[iEndpoint];
memcpy(ued, ptr, USB_DT_ENDPOINT_SIZE);
ptr += ued->bLength;
ued->wMaxPacketSize = cpu_to_le16(ued->wMaxPacketSize);
}
}
USB_Free( buffer);
buffer = NULL;
}
retval = 0;
free_and_error:
if(buffer != NULL)
USB_Free(buffer);
if(retval < 0)
USB_FreeDescriptors(udd);
return retval;
}
void USB_FreeDescriptors(usb_devdesc *udd)
{
int iConf, iInterface;
usb_configurationdesc *ucd;
usb_interfacedesc *uid;
if(udd->configurations != NULL)
{
for(iConf = 0; iConf < udd->bNumConfigurations; iConf++)
{
ucd = &udd->configurations[iConf];
if(ucd->interfaces != NULL)
{
for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
{
uid = &ucd->interfaces[iInterface];
if(uid->endpoints != NULL)
USB_Free(uid->endpoints);
if(uid->extra != NULL)
USB_Free(uid->extra);
}
USB_Free(ucd->interfaces);
}
}
USB_Free(udd->configurations);
}
}
s32 USB_WriteBlkMsg(struct ehci_device *fd,u8 bEndpoint,u32 wLength,void *rpData)
{
return ehci_bulk_message(fd,bEndpoint,wLength,rpData);
}
s32 USB_WriteCtrlMsg(struct ehci_device *fd,u8 bmRequestType,u8 bmRequest,u16 wValue,u16 wIndex,u16 wLength,void *rpData)
{
return __usb_control_message(fd,bmRequestType,bmRequest,wValue,wIndex,wLength,rpData,NULL,NULL);
}
s32 USB_GetConfiguration(struct ehci_device *fd, u8 *configuration)
{
u8 *_configuration;
s32 retval;
_configuration = USB_Alloc( 1);
if(_configuration == NULL)
return -ENOMEM;
retval = __usb_control_message(fd, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_GETCONFIG, 0, 0, 1, _configuration, NULL, NULL);
if(retval >= 0)
*configuration = *_configuration;
USB_Free( _configuration);
return retval;
}
s32 USB_SetConfiguration(struct ehci_device *fd, u8 configuration)
{
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_DEVICE), USB_REQ_SETCONFIG, configuration, 0, 0, NULL, NULL, NULL);
}
s32 USB_SetAlternativeInterface(struct ehci_device *fd, u8 interface, u8 alternateSetting)
{
// if(alternateSetting == 0)
// return -EINVAL;
return __usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_INTERFACE),
USB_REQ_SETINTERFACE, alternateSetting, interface, 0, NULL, NULL, NULL);
}
s32 USB_ClearHalt(struct ehci_device *fd, u8 endpoint)
{
s32 ret;
ret=__usb_control_message(fd, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_STANDARD | USB_CTRLTYPE_REC_ENDPOINT),
USB_REQ_CLEARFEATURE, USB_FEATURE_ENDPOINT_HALT, endpoint, 0, NULL, NULL, NULL);
return ret;
}