#define LOG_MODULE "p4iodrv-usb" #include #include #include // clang-format off // Don't format because the order is important here #include #include // clang-format on #include "p4io/cmd.h" #include "p4io/guid.h" #include "p4io/ioctl.h" #include "p4iodrv/usb.h" #include "util/log.h" #include "util/str.h" HANDLE p4io_usb_open(void) { HANDLE handle = INVALID_HANDLE_VALUE; wchar_t p4io_filename[MAX_PATH]; // game uses 1024, but it shouldn't be that long PSP_DEVICE_INTERFACE_DETAIL_DATA_W detail_data = NULL; HDEVINFO dev_info_set; dev_info_set = SetupDiGetClassDevsW(&p4io_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); if(dev_info_set == INVALID_HANDLE_VALUE) { log_warning("SetupDiGetClassDevs fail, is p4io device connected and driver installed?"); return INVALID_HANDLE_VALUE; } SP_DEVICE_INTERFACE_DATA interface_data; interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); if(!SetupDiEnumDeviceInterfaces(dev_info_set, NULL, &p4io_guid, 0, &interface_data)) { log_warning("SetupDiEnumDeviceInterfaces fail"); goto CLEANUP; } DWORD required_size; SetupDiGetDeviceInterfaceDetailW(dev_info_set, &interface_data, NULL, 0, &required_size, NULL); detail_data = malloc(required_size); detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); if(!SetupDiGetDeviceInterfaceDetailW(dev_info_set, &interface_data, detail_data, required_size, NULL, NULL)) { log_warning("SetupDiGetDeviceInterfaceDetailW fail"); goto CLEANUP; } wstr_cpy(p4io_filename, MAX_PATH, detail_data->DevicePath); wstr_cat(p4io_filename, MAX_PATH, L"\\p4io"); log_info("p4io found at path %ls", p4io_filename); handle = CreateFileW(p4io_filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if(handle == INVALID_HANDLE_VALUE) { log_warning("CreateFileW fail"); goto CLEANUP; } CLEANUP: free(detail_data); SetupDiDestroyDeviceInfoList(dev_info_set); return handle; } void p4io_usb_close(HANDLE p4io_handle) { if(p4io_handle != INVALID_HANDLE_VALUE) { CloseHandle(p4io_handle); } p4io_handle = INVALID_HANDLE_VALUE; } bool p4io_usb_read_jamma(HANDLE jamma_handle, uint32_t jamma[4]) { DWORD bytes_returned; if(!DeviceIoControl(jamma_handle, P4IO_IOCTL_READ_JAMMA_2, NULL, 0, jamma, sizeof(uint32_t[4]), &bytes_returned, NULL)) { log_warning("jamma read failed"); return false; } return true; } bool p4io_usb_read_device_name(HANDLE bulk_handle, char name[128]) { DWORD bytes_returned; if(!DeviceIoControl(bulk_handle, P4IO_IOCTL_GET_DEVICE_NAME, NULL, 0, name, 128, &bytes_returned, NULL)) { log_warning("p4io does not support get_name cmd"); return false; } return true; } bool p4io_usb_transfer( HANDLE bulk_handle, uint8_t cmd, uint8_t seq_no, const void *req_payload, size_t req_payload_len, void *resp_payload, size_t *resp_payload_len ) { DWORD bytes_requested; DWORD bytes_xferred; struct p4io_cmd_package cmd_buf; if(bulk_handle == INVALID_HANDLE_VALUE) { log_warning("p4io not open"); return false; } if(req_payload_len > sizeof(cmd_buf.payload)) { log_warning("request too big"); return false; } cmd_buf.header.sof = P4IO_SOF; cmd_buf.header.cmd = cmd; cmd_buf.header.seq_num = seq_no; cmd_buf.header.payload_len = req_payload_len; memcpy(cmd_buf.payload, req_payload, req_payload_len); bytes_requested = P4IO_CMD_HEADER_LEN + req_payload_len; if(!WriteFile(bulk_handle, &cmd_buf, bytes_requested, &bytes_xferred, 0)) { log_warning("WriteFile failed"); return false; } if(bytes_xferred != bytes_requested) { log_warning("WriteFile didn't finish"); return false; } // must be 65 bytes or requests can stall - only 64 will ever be returned if(!ReadFile(bulk_handle, &cmd_buf, 65, &bytes_xferred, 0)) { log_warning("ReadFile (%u) failed", (unsigned)bytes_requested); return false; } if(bytes_xferred >= sizeof(struct p4io_cmd_header)) { memcpy(resp_payload, cmd_buf.payload, *resp_payload_len); *resp_payload_len = cmd_buf.header.payload_len; if(cmd_buf.header.sof != P4IO_SOF) { log_warning("Response bad header"); return false; } if(seq_no != cmd_buf.header.seq_num) { log_warning("seq_num mismatch (ours %d != theirs %d)", seq_no, cmd_buf.header.seq_num); return false; } } else { *resp_payload_len = 0; } return true; }