mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-15 16:05:10 +01:00
223 lines
6.1 KiB
C
223 lines
6.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)
|
||
|
{
|
||
|
retval = -ENOMEM;
|
||
|
goto free_and_error;
|
||
|
}
|
||
|
|
||
|
retval = __usb_getdesc(fd, buffer, USB_DT_DEVICE, 0, USB_DT_DEVICE_SIZE);
|
||
|
if(retval < 0)
|
||
|
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)
|
||
|
{
|
||
|
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)
|
||
|
{
|
||
|
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)
|
||
|
{
|
||
|
retval = -ENOMEM;
|
||
|
goto free_and_error;
|
||
|
}
|
||
|
|
||
|
retval = __usb_getdesc(fd, buffer, USB_DT_CONFIG, iConf, ucd->wTotalLength);
|
||
|
if(retval < 0)
|
||
|
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)
|
||
|
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)
|
||
|
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)
|
||
|
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;
|
||
|
}
|