diff --git a/ezusb/src/ezusb.cpp b/ezusb/src/ezusb.cpp index 3a486f2..b6353e6 100644 --- a/ezusb/src/ezusb.cpp +++ b/ezusb/src/ezusb.cpp @@ -1,15 +1,76 @@ -/* TO BE COMPILED WITH VISUAL STUDIO SO THAT EXPORTS ARE PROPERLY MANGLED */ -#define _CRT_SECURE_NO_WARNINGS -#include +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" +#include "ezusb.h" extern "C" { // This file is in the Windows DDK available from Microsoft. #include +#include } #include #include #include "ezusb.h" +//#define DEBUG HANDLE g_hid_handle; +uint8_t g_dip_state = 0; +// GUID_DEVCLASS_HIDCLASS +static GUID hidclass_guid = {0x745a17a0, 0x74d3, 0x11d0, 0xb6, 0xfe, 0x00, 0xa0, 0xc9, 0x0f, 0x57, 0xda}; + +BOOLEAN get_device_path(wchar_t *lPath) +{ + + const GUID *guid = &hidclass_guid; + HidD_GetHidGuid(&hidclass_guid); +// Get device interface info set handle +// for all devices attached to system + HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // Function class devices. + if(hDevInfo == INVALID_HANDLE_VALUE) + return FALSE; + +// Retrieve a context structure for a device interface of a device information set. + BYTE buf[1024]; + PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)buf; + SP_DEVICE_INTERFACE_DATA spdid; + SP_DEVINFO_DATA spdd; + DWORD dwSize; + + spdid.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + +// Iterate through all the interfaces and try to match one based on +// the device number. + DWORD device_index = 0; + + for(DWORD i = 0; SetupDiEnumDeviceInterfaces(hDevInfo, NULL,guid, i, &spdid); i++) + { + // Get the device path. + dwSize = 0; + SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL); + if(dwSize == 0 || dwSize > sizeof(buf)) + continue; + + pspdidd->cbSize = sizeof(*pspdidd); + ZeroMemory((PVOID)&spdd, sizeof(spdd)); + spdd.cbSize = sizeof(spdd); + if(!SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, + dwSize, &dwSize, &spdd)) + continue; + + /* check if the device contains our wanted vid/pid */ + if ( wcsstr( pspdidd->DevicePath, L"vid_1ccf&pid_4148&mi_02" ) == NULL ) + { + continue; + } +#ifdef DEBUG + printf("\r\nDevice found at %S\r\n", &pspdidd->DevicePath); +#endif + //copy devpath into lPath + wcscpy(lPath, pspdidd->DevicePath); + SetupDiDestroyDeviceInfoList(hDevInfo); + return TRUE; + } + SetupDiDestroyDeviceInfoList(hDevInfo); + return FALSE; +} /** * Initialize the g_hid_handle global variable @@ -20,47 +81,52 @@ HANDLE g_hid_handle; * @return 0 on success, -1 on error */ static int controller_init(){ - FILE *file; - char path[256]; + static uint8_t err_count = 0; + wchar_t lPath[256]; + char path[256]; + FILE *file; - file = fopen("devicepath.dat", "r"); - if (file == NULL) + /* first check if there's a devicepath.dat override */ + file = fopen("devicepath.dat", "r"); + if (file != NULL) { - goto last_resort; + while ( fgets(path,256,file) != NULL ) + { + path[strcspn(path, "\r\n")] = 0; + g_hid_handle = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if ( g_hid_handle != INVALID_HANDLE_VALUE ) + { + fclose(file); + return 0; + } + } + fclose(file); } - while ( fgets(path,256,file) != NULL ) - { - path[strcspn(path, "\r\n")] = 0; - g_hid_handle = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if ( g_hid_handle != INVALID_HANDLE_VALUE ) - break; - } - fclose(file); + /* auto detect device path */ + if (!get_device_path(lPath)) + { + printf("\r\nPOPN MUSIC USB not detected.\r\n"); + err_count++; + if (err_count > 2){ + printf("Could not init device after multiple attempts. Exiting.\r\n"); + exit(1); + } + return -1; + } + g_hid_handle = CreateFile(lPath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if ( g_hid_handle == INVALID_HANDLE_VALUE ) { - goto last_resort; + printf("Could not open detected device (err = %x).\r\n", GetLastError()); + return -1; } return 0; - -last_resort: - g_hid_handle = CreateFile("\\\\?\\HID#VID_2341&PID_003E&MI_02#7&3156e204&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}", - GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if ( g_hid_handle != INVALID_HANDLE_VALUE ) - return 0; - - g_hid_handle = CreateFile("\\\\?\\HID#VID_2341&PID_8036&MI_02#7&63200bf&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}", - GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if ( g_hid_handle != INVALID_HANDLE_VALUE ) - return 0; - - printf("Couldn't open device. Make sure devicepath.dat exists and contains the correct path.\r\n"); - return -1; } /** - * Read buttons state from the Arduino and convert them into Pop'n Music format + * Read buttons state from the board and convert them into Pop'n Music format * * Pop'n Music processes button states as a uint32_t bitfield with the following format : * bits 0 (LSB) to 5 : nothing @@ -68,41 +134,50 @@ last_resort: * bit 7 : test * bits 8 to 16 : buttons 1 to 9 * bit 22 : coin mech + * bits 24 to 27 : dip 1 to 4 * * @param pad_bits[out] button state bitfield * @return 0 on success, -1 on error */ static int controller_read_buttons(uint32_t *pad_bits){ - DWORD BytesRead = 0; - byte res[4]; - unsigned char buf[6]; // gamepad report length is 3 bytes in Arduino firmware, doubled because NumInputBuffer is set to 2 + DWORD uint8_tsRead = 0; + uint8_t res[4]; + unsigned char buf[6]; // gamepad report length is 3 uint8_ts in firmware, doubled because NumInputBuffer is set to 2 - buf[0] = 0x04; // gamepad report ID is 4 in Arduino firmware + buf[0] = 0x04; // gamepad report ID is 4 in firmware *pad_bits = 0; - ReadFile(g_hid_handle, buf, 6, &BytesRead, NULL); - // BytesRead should either be 6 (if it successfully read 2 reports) or 3 (only one) - if ( BytesRead != 6 && BytesRead != 3 ) + ReadFile(g_hid_handle, buf, 6, &uint8_tsRead, NULL); + // uint8_tsRead should either be 6 (if it successfully read 2 reports) or 3 (only one) + if ( uint8_tsRead != 6 && uint8_tsRead != 3 ) { +#ifdef DEBUG + printf("HID read error (got %u uint8_ts)\n",uint8_tsRead); +#endif return -1; } - /* HID read ok, convert latest report bytes to pop'n bitfield */ + /* HID read ok, convert latest report uint8_ts to pop'n bitfield */ res[3] = 0; - res[2] = (buf[BytesRead-1]<<3 | buf[BytesRead-1]) & 0x41; - res[1] = buf[BytesRead-2]; + res[2] = (buf[uint8_tsRead-1]<<3 | buf[uint8_tsRead-1]) & 0x41; + res[1] = buf[uint8_tsRead-2]; res[0] = 0; - buf[BytesRead-1] >>= 1; - if ( buf[BytesRead-1]&1 ) res[0] |= 0x80; - buf[BytesRead-1] >>= 1; - if ( buf[BytesRead-1]&1 ) res[0] |= 0x40; + buf[uint8_tsRead-1] >>= 1; + if ( buf[uint8_tsRead-1]&1 ) res[0] |= 0x80; + buf[uint8_tsRead-1] >>= 1; + if ( buf[uint8_tsRead-1]&1 ) res[0] |= 0x40; *pad_bits = *(uint32_t *)res; + + /* dip switches */ + *pad_bits |= g_dip_state << 24; + #ifdef DEBUG for (int i = 0; i<32; i++){ printf("%c",( ((uint32_t )*pad_bits>>(31-i))&1)?'1':'0'); if (((i+1)%4)==0) printf(" "); } printf("\n"); + if (*pad_bits & 0x8000000) printf("31kHz mode\n"); #endif return 0; } @@ -119,9 +194,9 @@ static int controller_read_buttons(uint32_t *pad_bits){ * @return 0 on success, -1 on error */ static int controller_write_leds(int32_t lamp_bits){ - DWORD BytesWritten = 0; - byte *src = (byte*) &lamp_bits; //cast as byte array for fast conversion - byte buf[5]; // HID lights report length is 5 bytes in Arduino firmware + DWORD bytesWritten = 0; + uint8_t *src = (uint8_t*) &lamp_bits; //cast as uint8_t array for fast conversion + uint8_t buf[5]; // HID lights report length is 5 bytes in Arduino firmware /* convert bitfield into HID Report format */ buf[4] = 0; @@ -131,12 +206,12 @@ static int controller_write_leds(int32_t lamp_bits){ buf[0] = 0x05; // HID lights report id is 5 in Arduino firmware /* send HID Report */ - WriteFile(g_hid_handle, buf, 5, &BytesWritten, NULL); - if ( BytesWritten == 5 ) + WriteFile(g_hid_handle, buf, 5, &bytesWritten, NULL); + if ( bytesWritten == 5 ) return 0; -#ifdef DEBUG - printf("Error sending HID report (%u bytes written)\r\n",BytesWritten); +#ifdef DEBUG_LAMP + printf("Error sending HID report (%u bytes written)\r\n",bytesWritten); #endif return -1; } @@ -144,7 +219,7 @@ static int controller_write_leds(int32_t lamp_bits){ /* EZUSB EXPORTS */ -#if POPN15_FORMAT == 1 +#ifdef POPN15_FORMAT extern "C" { #endif @@ -190,7 +265,10 @@ __declspec(dllexport) int __cdecl usbPadRead(unsigned long *pad_bits) { } __declspec(dllexport) int __cdecl usbPadReadLast(uint8_t *a1) { - memset(a1, 0, 4); + /* This memset is what is being done by the usual hooks. + * However, it breaks Pop'n 15~18 compatibility and seems + * to have no effect on later Pop'n so I removed it... */ + //memset(a1, 0, 40); return 0; } @@ -229,7 +307,7 @@ __declspec(dllexport) int __cdecl usbStart(int i) { return -1; } - bool hidres = HidD_SetNumInputBuffers( + BOOLEAN hidres = HidD_SetNumInputBuffers( g_hid_handle, 2); if (!hidres) @@ -238,12 +316,27 @@ __declspec(dllexport) int __cdecl usbStart(int i) { return -1; } + /* read dip switches */ + uint8_t feat[2] = {0x06, 0x00}; + if (!HidD_GetFeature(g_hid_handle, &feat, 2)) + { + printf("error %d getFeature\n",GetLastError()); + }; + g_dip_state = feat[1]; + +#ifdef FORCE_DIP4 + g_dip_state |= 0x08; +#endif /* light everything for 1 sec to get visual confirmation * the device is working */ controller_write_leds((uint32_t) 0xFFFFFFFF); Sleep(1000); controller_write_leds((uint32_t) 0x00000000); +#ifdef DEBUG + printf("Managed to open device %x\n",g_hid_handle); + printf("Dip state is %x\n", g_dip_state); +#endif return 0; } @@ -259,15 +352,19 @@ __declspec(dllexport) int __cdecl usbWdtStartDone() { return 0; } -#if POPN15_FORMAT == 1 +#ifdef POPN15_FORMAT } #endif -int __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, void *) { + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD fdwReason, + LPVOID lpReserved + ) { if (fdwReason == 1) { //https://blogs.msdn.microsoft.com/larryosterman/2004/06/03/little-known-win32-apis-disablethreadlibrarycalls/ - DisableThreadLibraryCalls(hinstDLL); + DisableThreadLibraryCalls(hModule); } return 1; -} \ No newline at end of file +}