#include #include #include #include #include #include "descriptors.h" #include "usb.h" #include "psgroove.h" /********************************************************************************/ /*------------------------------------------------------------------------------*/ /* PsGroove Emulation */ /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ #define PORT_EMPTY 0x0100 /* powered only */ #define PORT_FULL 0x0103 /* connected, enabled, powered, full-speed */ #define C_PORT_CONN 0x0001 /* connection */ #define C_PORT_RESET 0x0010 /* reset */ #define C_PORT_NONE 0x0000 /* no change */ unsigned short port_status[6] = { PORT_EMPTY, PORT_EMPTY, PORT_EMPTY, PORT_EMPTY, PORT_EMPTY, PORT_EMPTY }; unsigned short port_change[6] = { C_PORT_NONE, C_PORT_NONE, C_PORT_NONE, C_PORT_NONE, C_PORT_NONE, C_PORT_NONE }; enum { init, wait_hub_ready, hub_ready, p1_wait_reset, p1_wait_enumerate, p1_ready, p2_wait_reset, p2_wait_enumerate, p2_ready, p3_wait_reset, p3_wait_enumerate, p3_ready, p2_wait_disconnect, p4_wait_connect, p4_wait_reset, p4_wait_enumerate, p4_ready, p5_wait_reset, p5_wait_enumerate, p5_challenged, p5_responded, p3_wait_disconnect, p3_disconnected, p5_wait_disconnect, p5_disconnected, p4_wait_disconnect, p4_disconnected, p1_wait_disconnect, p1_disconnected, p6_wait_reset, p6_wait_enumerate, done, } state = init; unsigned char hub_int_response = 0x00; unsigned char hub_int_force_data0 = 0; int last_port_conn_clear = 0; int last_port_reset_clear = 0; unsigned char port_addr[7] = { -1, -1, -1, -1, -1, -1, -1 }; unsigned char port_cur = -1; /*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/ /*PsGroove_Timer */ /*------------------------------------------------------------------------------*/ volatile unsigned char expire = 0; /* counts down every 10 milliseconds */ void PsGroove_Timer( void ) { if (expire > 0) expire--; } /*------------------------------------------------------------------------------*/ /*PsGroove_Panic */ /*------------------------------------------------------------------------------*/ void PsGroove_Panic() { //TODO: Don't Panic! } /*------------------------------------------------------------------------------*/ /*PsGroove_Switch_Port */ /*------------------------------------------------------------------------------*/ void PsGroove_Switch_Port(int8_t port) { if (port_cur == port) return; port_cur = port; if (port_addr[port] < 0) port_addr[port] = 0; //TODO: I can't port this two lines //UDADDR = port_addr[port] & 0x7f; //UDADDR |= (1 << ADDEN); } /*------------------------------------------------------------------------------*/ /*PsGroove_Connect_Port */ /*------------------------------------------------------------------------------*/ void PsGroove_Connect_Port(int port) { last_port_reset_clear = 0; hub_int_response = (1 << port); port_status[port - 1] = PORT_FULL; port_change[port - 1] = C_PORT_CONN; } /*------------------------------------------------------------------------------*/ /*PsGroove_Disconnect_Port */ /*------------------------------------------------------------------------------*/ void PsGroove_Disconnect_Port(int port) { last_port_conn_clear = 0; hub_int_response = (1 << port); port_status[port - 1] = PORT_EMPTY; port_change[port - 1] = C_PORT_CONN; } /*------------------------------------------------------------------------------*/ /*PsGroove_GetDescription */ /*------------------------------------------------------------------------------*/ unsigned short PsGroove_GetDescription(unsigned char DescriptorType, unsigned char DescriptorNumber, unsigned short wLength, const void** const DescriptorAddress) { void* Address = NULL; unsigned short Size = 0; switch(DescriptorType) { case 0x01: //DTYPE_Device switch (port_cur) { //case 0: // Address = (void *) HUB_Device_Descriptor; // Size = sizeof(HUB_Device_Descriptor); // break; case 1: Address = (void *) port1_device_descriptor; Size = sizeof(port1_device_descriptor); break; case 2: Address = (void *) port2_device_descriptor; Size = sizeof(port2_device_descriptor); break; case 3: Address = (void *) port3_device_descriptor; Size = sizeof(port3_device_descriptor); break; case 4: Address = (void *) port4_device_descriptor; Size = sizeof(port4_device_descriptor); break; case 5: Address = (void *) port5_device_descriptor; Size = sizeof(port5_device_descriptor); break; case 6: Address = (void *) port6_device_descriptor; Size = sizeof(port6_device_descriptor); break; } break; case 0x02: //DTYPE_Configuration switch (port_cur) { //case 0: // Address = (void *) HUB_Config_Descriptor; // Size = sizeof(HUB_Config_Descriptor); // break; case 1: // 4 configurations are the same. // For the initial 8-byte request, we give a different // length response than in the full request. if (DescriptorNumber < 4) { if (wLength == 8) { Address = (void *) port1_short_config_descriptor; Size = sizeof(port1_short_config_descriptor); } else { Address = (void *) port1_config_descriptor; Size = sizeof(port1_config_descriptor); } if (DescriptorNumber == 3 && wLength > 8) { state = p1_ready; expire = 10; } } break; case 2: // only 1 config Address = (void *) port2_config_descriptor; Size = sizeof(port2_config_descriptor); state = p2_ready; expire = 15; break; case 3: // 2 configurations are the same Address = (void *) port3_config_descriptor; Size = sizeof(port3_config_descriptor); if (DescriptorNumber == 1 && wLength > 8) { state = p3_ready; expire = 10; } break; case 4: // 3 configurations if (DescriptorNumber == 0) { Address = (void *) port4_config_descriptor_1; Size = sizeof(port4_config_descriptor_1); } else if (DescriptorNumber == 1) { if (wLength == 8) { Address = (void *) port4_short_config_descriptor_2; Size = sizeof(port4_short_config_descriptor_2); } else { Address = (void *) port4_config_descriptor_2; Size = sizeof(port4_config_descriptor_2); } } else if (DescriptorNumber == 2) { Address = (void *) port4_config_descriptor_3; Size = sizeof(port4_config_descriptor_3); if (wLength > 8) { state = p4_ready; expire = 20; // longer seems to help this one? } } break; case 5: // 1 config Address = (void *) port5_config_descriptor; Size = sizeof(port5_config_descriptor); break; case 6: // 1 config Address = (void *) port6_config_descriptor; Size = sizeof(port6_config_descriptor); break; } break; //case 0x29: // HUB descriptor (always to port 0 we'll assume) // switch (port_cur) { // case 0: // Address = (void *) HUB_Hub_Descriptor; // Size = sizeof(HUB_Hub_Descriptor); // break; // } // break; } return Size; } /*------------------------------------------------------------------------------*/ /*PsGroove_UnhandledControlRequest */ /*------------------------------------------------------------------------------*/ void PsGroove_UnhandledControlRequest(struct DeviceRequest USB_ControlRequest) { if (port_cur == 6 && USB_ControlRequest.bRequest == 0xAA) { /* holy crap, it worked! */ //Endpoint_ClearSETUP(); //Endpoint_ClearIN(); //Endpoint_ClearStatusStage(); state = done; return; } if (port_cur == 5 && USB_ControlRequest.bRequest == 11 /*REQ_SetInterface*/) { /* can ignore this */ //Endpoint_ClearSETUP(); //Endpoint_ClearIN(); //Endpoint_ClearStatusStage(); return; } if (port_cur == 0 && USB_ControlRequest.bmRequestType == 0xA0 && USB_ControlRequest.bRequest == 0x00 && // GET HUB STATUS USB_ControlRequest.wValue == 0x00 && USB_ControlRequest.wIndex == 0x00 && USB_ControlRequest.wLength == 0x04) { //Endpoint_ClearSETUP(); //Endpoint_Write_Word_LE(0x0000); // wHubStatus //Endpoint_Write_Word_LE(0x0000); // wHubChange //Endpoint_ClearIN(); //Endpoint_ClearStatusStage(); unsigned short Empty[] = {0x0000, 0x0000}; UsbWriteData(Empty, 4); // wHubStatus, wHubChange return; } if (port_cur == 0 && USB_ControlRequest.bmRequestType == 0xA3 && USB_ControlRequest.bRequest == 0x00 && // GET PORT STATUS USB_ControlRequest.wValue == 0x00 && USB_ControlRequest.wLength == 0x04) { unsigned char p = USB_ControlRequest.wIndex; if (p < 1 || p > 6) return; //Endpoint_ClearSETUP(); //Endpoint_Write_Word_LE(port_status[p - 1]); // wHubStatus //Endpoint_Write_Word_LE(port_change[p - 1]); // wHubChange //Endpoint_ClearIN(); //Endpoint_ClearStatusStage(); unsigned char Package[] = {port_status[p - 1], port_status[p], port_change[p - 1], port_change[p]}; UsbWriteData(Package, 4); // wHubStatus, wHubChange return; } if (port_cur == 0 && USB_ControlRequest.bmRequestType == 0x23 && USB_ControlRequest.bRequest == 0x03 && // SET_FEATURE USB_ControlRequest.wLength == 0x00) { unsigned char p = USB_ControlRequest.wIndex; if (p < 1 || p > 6) return; //Endpoint_ClearSETUP(); //Endpoint_ClearIN(); //Endpoint_ClearStatusStage(); switch(USB_ControlRequest.wValue) { case 0x0008: // PORT_POWER if (p == 6 && state == init) { /* after the 6th port is powered, wait a bit and continue */ state = hub_ready; expire = 15; } break; case 0x0004: // PORT_RESET hub_int_response = (1 << p); port_change[p - 1] |= C_PORT_RESET; break; } return; } if (port_cur == 0 && USB_ControlRequest.bmRequestType == 0x23 && USB_ControlRequest.bRequest == 0x01 && // CLEAR_FEATURE USB_ControlRequest.wLength == 0x00) { unsigned char p = USB_ControlRequest.wIndex; if (p < 1 || p > 6) return; //Endpoint_ClearSETUP(); //Endpoint_ClearIN(); //Endpoint_ClearStatusStage(); switch(USB_ControlRequest.wValue) { case 0x0010: // C_PORT_CONNECTION port_change[p - 1] &= ~C_PORT_CONN; last_port_conn_clear = p; break; case 0x0014: // C_PORT_RESET port_change[p - 1] &= ~C_PORT_RESET; last_port_reset_clear = p; break; } return; } PsGroove_Panic(); } /*------------------------------------------------------------------------------*/ /*PsGroove_JIG_Task */ /*------------------------------------------------------------------------------*/ const unsigned char jig_response[64] = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xee, 0x78, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xee, 0x88, 0x80, 0x00, 0x00, 0x00, 0x00, 0x33, 0xe7, 0x20, 0xe8, 0x83, 0xff, 0xf0, 0xe8, 0x63, 0xff, 0xf8, 0xe8, 0xa3, 0x00, 0x18, 0x38, 0x63, 0x10, 0x00, 0x7c, 0x04, 0x28, 0x00, 0x40, 0x82, 0xff, 0xf4, 0x38, 0xc3, 0xf0, 0x20, 0x7c, 0xc9, 0x03, 0xa6, 0x4e, 0x80, 0x04, 0x20, 0x04, 0x00, 0x00, 0x00, }; void PsGroove_JIG_Task(void) { static int bytes_out = 0, bytes_in = 0; unsigned char buffer[0x100]; //Endpoint_Discard_Stream(8, NO_STREAM_CALLBACK); UsbReadData(buffer, 8); bytes_out += 8; if (bytes_out >= 64) { state = p5_challenged; expire = 50; // was 90 } if (state == p5_challenged && expire == 0) { if (bytes_in < 64) { UsbWriteData(&jig_response[bytes_in], 8); bytes_in += 8; if (bytes_in >= 64) { state = p5_responded; expire = 15; } } } } /*------------------------------------------------------------------------------*/ /*PsGroove_Start */ /*------------------------------------------------------------------------------*/ void PsGroove_Start() { //TODO: start the timer.... (PsGroove_Timer each 10 ms.) state = init; PsGroove_Switch_Port(0); for (;;) { /*if (port_cur == 0) HUB_Task();*/ if (port_cur == 5) PsGroove_JIG_Task(); // connect 1 if (state == hub_ready && expire == 0) { PsGroove_Connect_Port(1); state = p1_wait_reset; } if (state == p1_wait_reset && last_port_reset_clear == 1) { PsGroove_Switch_Port(1); state = p1_wait_enumerate; } // connect 2 if (state == p1_ready && expire == 0) { PsGroove_Switch_Port(0); PsGroove_Connect_Port(2); state = p2_wait_reset; } if (state == p2_wait_reset && last_port_reset_clear == 2) { PsGroove_Switch_Port(2); state = p2_wait_enumerate; } // connect 3 if (state == p2_ready && expire == 0) { PsGroove_Switch_Port(0); PsGroove_Connect_Port(3); state = p3_wait_reset; } if (state == p3_wait_reset && last_port_reset_clear == 3) { PsGroove_Switch_Port(3); state = p3_wait_enumerate; } // disconnect 2 if (state == p3_ready && expire == 0) { PsGroove_Switch_Port(0); PsGroove_Disconnect_Port(2); state = p2_wait_disconnect; } if (state == p2_wait_disconnect && last_port_conn_clear == 2) { state = p4_wait_connect; expire = 15; } // connect 4 if (state == p4_wait_connect && expire == 0) { PsGroove_Connect_Port(4); state = p4_wait_reset; } if (state == p4_wait_reset && last_port_reset_clear == 4) { PsGroove_Switch_Port(4); state = p4_wait_enumerate; } // connect 5 if (state == p4_ready && expire == 0) { PsGroove_Switch_Port(0); /* When first connecting port 5, we need to have the wrong data toggle for the PS3 to respond */ hub_int_force_data0 = 1; PsGroove_Connect_Port(5); state = p5_wait_reset; } if (state == p5_wait_reset && last_port_reset_clear == 5) { PsGroove_Switch_Port(5); state = p5_wait_enumerate; } // disconnect 3 if (state == p5_responded && expire == 0) { PsGroove_Switch_Port(0); /* Need wrong data toggle again */ hub_int_force_data0 = 1; PsGroove_Disconnect_Port(3); state = p3_wait_disconnect; } if (state == p3_wait_disconnect && last_port_conn_clear == 3) { state = p3_disconnected; expire = 45; } // disconnect 5 if (state == p3_disconnected && expire == 0) { PsGroove_Switch_Port(0); PsGroove_Disconnect_Port(5); state = p5_wait_disconnect; } if (state == p5_wait_disconnect && last_port_conn_clear == 5) { state = p5_disconnected; expire = 20; } // disconnect 4 if (state == p5_disconnected && expire == 0) { PsGroove_Switch_Port(0); PsGroove_Disconnect_Port(4); state = p4_wait_disconnect; } if (state == p4_wait_disconnect && last_port_conn_clear == 4) { state = p4_disconnected; expire = 20; } // disconnect 1 if (state == p4_disconnected && expire == 0) { PsGroove_Switch_Port(0); PsGroove_Disconnect_Port(1); state = p1_wait_disconnect; } if (state == p1_wait_disconnect && last_port_conn_clear == 1) { state = p1_disconnected; expire = 20; } // connect 6 if (state == p1_disconnected && expire == 0) { PsGroove_Switch_Port(0); PsGroove_Connect_Port(6); state = p6_wait_reset; } if (state == p6_wait_reset && last_port_reset_clear == 6) { PsGroove_Switch_Port(6); state = p6_wait_enumerate; } // done if (state == done) { //TODO: Great! } } }