From bc47b562ff48cf704295fa10da5637469cec6d80 Mon Sep 17 00:00:00 2001 From: CrazyRedMachine Date: Sat, 8 Aug 2020 23:22:10 +0200 Subject: [PATCH] ezusb driver and optional devicepath.dat --- ModeSwitch/C/modeswitch.exe | Bin 247272 -> 247344 bytes ModeSwitch/C/src/CMakeLists.txt | 9 +- ModeSwitch/C/src/modeswitch.cpp | 72 +++++++-- ModeSwitch/readme.md | 2 + README.md | 6 + ezusb/ezusb-popn15.dll | Bin 0 -> 10752 bytes ezusb/ezusb.dll | Bin 0 -> 10752 bytes ezusb/readme.md | 19 +++ ezusb/src/CMakeLists.txt | 12 ++ ezusb/src/ezusb.cpp | 273 ++++++++++++++++++++++++++++++++ ezusb/src/ezusb.h | 37 +++++ ezusb/src/lib/hid.lib | Bin 0 -> 12158 bytes 12 files changed, 405 insertions(+), 25 deletions(-) create mode 100644 ezusb/ezusb-popn15.dll create mode 100644 ezusb/ezusb.dll create mode 100644 ezusb/readme.md create mode 100644 ezusb/src/CMakeLists.txt create mode 100644 ezusb/src/ezusb.cpp create mode 100644 ezusb/src/ezusb.h create mode 100644 ezusb/src/lib/hid.lib diff --git a/ModeSwitch/C/modeswitch.exe b/ModeSwitch/C/modeswitch.exe index b3d540f724c1d2c844a1b19e859f3a4bd30e3a49..7920046286a2db98a746083e977afcbe861419ac 100644 GIT binary patch delta 21176 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 ORK6Tq9&VFf(EUFs^EFZc delta 20716 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

XW z@~eSZC&zxlW7V^#fwWk8b^%Blx>X(f!pDz+T&l8Sx(Nt+EPCW;A!fznfC)q#<|g_* zf+PYN3?6gOE_j5e1W1q=b|Qz=JgNf}XVuojk0?4R#H@JE0cp_jsZB_TODKy&>;CN3 zC3&S;B*rSnpDR3iiw4{Va@(qr_XUqtL|yQ7M;w~w^wOd{)T*sChwyKkussm4#-g}sog-tI5YE{tO8`t4`E*X z9hSG1`S-zdtjO|i@d=PutW@6uA`bIB`Kv&z^mGFeE}HYz%PoQs?A$Co68|cp!%A#8 z5G=2wnx!ajJ<2WO2C2#5i*q1Yqn9^J0aKQsjHezJ+H!%23CV0yd^=K#$=HnS1d?JU z)yV(VjM0{2<%am&`V7W|dA7R(B(q1kVRgnzu@3LZwv5zg;1P!%PPJQZ1G#GzJMjlw z;&p*pvmKtA+2Fe$3n&zjb<2kV5r=tfjR%qsL~WZPyQmockW{N?h`+nq*Mk_uU*!~K zka9C($Sx?#%p%p|)@TmW;zx{$XMN%@o8JgT55$~a`+W z&3l^}-1!)0;l(@}mxVbHY3MPntc-F?NCQO766N4YfLe1b4g*QGkjl#`OwT87J%JZa zoZ&AYL*hkPf$u=@Tu;s$vNQ6FR%Vf0E1rLV=RuEhq3SCj;xLExcOc$Y@v+Av)GjM2 zPayAGPxIk`#PnuXqz7U>Vb4-{^cFk@AmZ*}mMQ=eWo3RHkQ(rqvuqELPV<_`kiHau zKZq5fRa=|DRBq+m!IW zc4E~%dIYy0keHqrh|wx$>HAjE9qft8?u?b#c!-I{ z6v&wy@C1-^R#xT-9w6p*-clgqFgIY^Bgj!8*5m&bAe~kbeRDXVcB|OD4 #include +HANDLE g_hidHandle; + +/** + * Initialize the g_hidHandle global variable + * It will attempt to read paths from devicepath.dat file if it exists until it finds one which works. + * If nothing is found, as a last resort it will try the two default paths from the Due and Leonardo + * versions of the firmware. + * + * @return 0 on success, -1 on error + */ +static int controller_init(){ + FILE *file; + char path[256]; + + file = fopen("devicepath.dat", "r"); + if (file == NULL) + { + goto last_resort; + } + + while ( fgets(path,256,file) != NULL ) + { + path[strcspn(path, "\r\n")] = 0; + g_hidHandle = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if ( g_hidHandle != INVALID_HANDLE_VALUE ) + break; + } + fclose(file); + + if ( g_hidHandle == INVALID_HANDLE_VALUE ) + { + goto last_resort; + } + return 0; + +last_resort: + g_hidHandle = 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_hidHandle != INVALID_HANDLE_VALUE ) + return 0; + + g_hidHandle = 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_hidHandle != INVALID_HANDLE_VALUE ) + return 0; + + printf("Couldn't open device. Make sure devicepath.dat exists and contains the correct path.\r\n"); + return -1; +} + int main(int argc, char* argv[]) { - FILE *file; - char path[256]; - HANDLE hidHandle; char OutputReport[5]; int res; int mode; @@ -25,18 +73,8 @@ int main(int argc, char* argv[]) printf("Invalid mode value %d\r\n", mode); return 2; } - - file = fopen("devicepath.dat", "r"); - while ( fgets(path,256,file) != NULL ) - { - path[strcspn(path, "\r\n")] = 0; - hidHandle = CreateFile(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if ( hidHandle != INVALID_HANDLE_VALUE ) - break; - } - fclose(file); - - if ( hidHandle == INVALID_HANDLE_VALUE ) + + if ( controller_init() == -1 ) { printf("Couldn't open device. Make sure devicepath.dat contains the correct path.\r\n"); return 3; @@ -48,7 +86,7 @@ int main(int argc, char* argv[]) OutputReport[3] = 0x00; OutputReport[4] = mode+16; //mode+magicbit - WriteFile(hidHandle, OutputReport, 5, &BytesWritten, NULL); + WriteFile(g_hidHandle, OutputReport, 5, &BytesWritten, NULL); if ( BytesWritten == 5 ) { res = 0; @@ -74,6 +112,6 @@ int main(int argc, char* argv[]) res = 4; } - CloseHandle(hidHandle); + CloseHandle(g_hidHandle); return res; } diff --git a/ModeSwitch/readme.md b/ModeSwitch/readme.md index ef1e1b0..4efe56c 100644 --- a/ModeSwitch/readme.md +++ b/ModeSwitch/readme.md @@ -38,6 +38,8 @@ The included devicepath.dat should work with both Due and Leonardo versions out devicepath.dat file should contain the device path on its own on a single line. Multiple paths on multiple lines should work too in which case it will open the first valid path it finds. +If no valid path is found or if there is no `devicepath.dat` file, it will attempt to open the default paths from the Due and Leonardo versions (same as the ones found in this included devicepath file). + ### spicetools open ```%appdata%/spicetools.xml```, look for a "devid" value starting with ```\\?\HID#VID_2341&PID_003E``` (Due) or ```\\?\HID#VID_2341&PID_8036``` (Leonardo) diff --git a/README.md b/README.md index 27870f9..78efa9b 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,12 @@ The 00 key is mapped to comma (for direct compatibility with spicetools) and the It also has a cool light animation on boot which you can easily adapt to your liking :) +## ezusb driver + +The I/O is HID so it can be mapped with the usual IO emulation tools, but it can also be used without emulation, just like an official IOBoard, provided you replace the original `ezusb.dll` file with the one from this repo. + +This way the firmware is fully compatible with anything that works on an official cabinet (PopnForwarder (a bit silly but why not :D), DJMame...) + ## Light modes There are 4 different modes : diff --git a/ezusb/ezusb-popn15.dll b/ezusb/ezusb-popn15.dll new file mode 100644 index 0000000000000000000000000000000000000000..1583f47ad485e4e5a3821a015e16b4ba806114dd GIT binary patch literal 10752 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 amt(hMpM!IGTp?GlYp3fmyxIMEo__}vVC&WZ literal 0 HcmV?d00001 diff --git a/ezusb/ezusb.dll b/ezusb/ezusb.dll new file mode 100644 index 0000000000000000000000000000000000000000..bd339aaeb67ed5cebe9655b09cc9a6be3fc7c086 GIT binary patch literal 10752 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 +extern "C" { +// This file is in the Windows DDK available from Microsoft. +#include +} +#include +#include +#include "ezusb.h" + +HANDLE g_hid_handle; + +/** + * Initialize the g_hid_handle global variable + * It will attempt to read paths from devicepath.dat file if it exists until it finds one which works. + * If nothing is found, as a last resort it will try the two default paths from the Due and Leonardo + * versions of the firmware. + * + * @return 0 on success, -1 on error + */ +static int controller_init(){ + FILE *file; + char path[256]; + + 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 = 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); + + if ( g_hid_handle == INVALID_HANDLE_VALUE ) + { + goto last_resort; + } + 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 + * + * Pop'n Music processes button states as a uint32_t bitfield with the following format : + * bits 0 (LSB) to 5 : nothing + * bit 6 : service + * bit 7 : test + * bits 8 to 16 : buttons 1 to 9 + * bit 22 : coin mech + * + * @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 + + buf[0] = 0x04; // gamepad report ID is 4 in Arduino 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 ) + { + return -1; + } + + /* HID read ok, convert latest report bytes to pop'n bitfield */ + res[3] = 0; + res[2] = (buf[BytesRead-1]<<3 | buf[BytesRead-1]) & 0x41; + res[1] = buf[BytesRead-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; + *pad_bits = *(uint32_t *)res; +#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"); +#endif + return 0; +} + +/** + * Read lights state and send the corresponding HID report to the Arduino + * + * Pop'n Music sends lights state as a int32_t bitfield with the following format : + * bits 0 (LSB) to 4 : neons from top to bottom + * bits 8 to 11 : side lamps (left blue, left red, right blue, right red) + * bits 23 to 31 : button lamps from left to right + * + * @param lamp_bits[in] lamp state bitfield + * @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 + + /* convert bitfield into HID Report format */ + buf[4] = 0; + buf[3] = (src[1] >> 2); + buf[2] = (src[1] << 6) | (src[0] << 1) | (src[3] >> 7); + buf[1] = (src[3] << 1) | (src[2] >> 7); + 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 ) + return 0; + +#ifdef DEBUG + printf("Error sending HID report (%u bytes written)\r\n",BytesWritten); +#endif + return -1; +} + + +/* EZUSB EXPORTS */ + +#if POPN15_FORMAT == 1 +extern "C" { +#endif + +__declspec(dllexport) int __cdecl usbCheckAlive() { + return 1; +} + +__declspec(dllexport) int __cdecl usbCheckSecurityNew(int i) { + return 0; +} + +__declspec(dllexport) int __cdecl usbCoinGet(int i) { + return 0; +} + +__declspec(dllexport) int __cdecl usbCoinMode(int i) { + return 0; +} + +__declspec(dllexport) int __cdecl usbEnd() { + CloseHandle(g_hid_handle); + return 0; +} + +__declspec(dllexport) int __cdecl usbFirmResult() { + return 0; +} + +__declspec(dllexport) int __cdecl usbGetKEYID(unsigned char *a, int i) { + return 0; +} + +__declspec(dllexport) int __cdecl usbGetSecurity(int i, unsigned char *a) { + return 0; +} + +__declspec(dllexport) int __cdecl usbLamp(int32_t lamp_bits) { + return controller_write_leds(lamp_bits); +} + +__declspec(dllexport) int __cdecl usbPadRead(unsigned long *pad_bits) { + return controller_read_buttons((uint32_t *)pad_bits); +} + +__declspec(dllexport) int __cdecl usbPadReadLast(uint8_t *a1) { + memset(a1, 0, 4); + return 0; +} + +__declspec(dllexport) int __cdecl usbSecurityInit() { + return 0; +} + +__declspec(dllexport) int __cdecl usbSecurityInitDone() { + return 0; +} + +__declspec(dllexport) int __cdecl usbSecuritySearch() { + return 0; +} + +__declspec(dllexport) int __cdecl usbSecuritySearchDone() { + return 0; +} + +__declspec(dllexport) int __cdecl usbSecuritySelect(int i) { + return 0; +} + +__declspec(dllexport) int __cdecl usbSecuritySelectDone() { + return 0; +} + +__declspec(dllexport) int __cdecl usbSetExtIo(int i) { + return 0; +} + +__declspec(dllexport) int __cdecl usbStart(int i) { + if (controller_init() == -1) + { + printf("Could not init device.\n"); + return -1; + } + + bool hidres = HidD_SetNumInputBuffers( + g_hid_handle, + 2); + if (!hidres) + { + printf("error %d setnuminputbuff\n",GetLastError()); + return -1; + } + + /* 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); + + return 0; +} + +__declspec(dllexport) int __cdecl usbWdtReset() { + return 0; +} + +__declspec(dllexport) int __cdecl usbWdtStart(int i) { + return 0; +} + +__declspec(dllexport) int __cdecl usbWdtStartDone() { + return 0; +} + +#if POPN15_FORMAT == 1 +} +#endif + +int __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, void *) { + if (fdwReason == 1) { + //https://blogs.msdn.microsoft.com/larryosterman/2004/06/03/little-known-win32-apis-disablethreadlibrarycalls/ + DisableThreadLibraryCalls(hinstDLL); + } + + return 1; +} \ No newline at end of file diff --git a/ezusb/src/ezusb.h b/ezusb/src/ezusb.h new file mode 100644 index 0000000..0cc071a --- /dev/null +++ b/ezusb/src/ezusb.h @@ -0,0 +1,37 @@ +#ifndef EZUSB_UPC_EZUSB_H +#define EZUSB_UPC_EZUSB_H + +/* Pop'n Music Adventure ezusb.dll was compiled in C and thus used unmangled function names + * set this POPN15_FORMAT to 1 to compile a compatible version */ +#define POPN15_FORMAT 0 + +#if POPN15_FORMAT == 1 +extern "C" { +#endif +__declspec(dllexport) int __cdecl usbCheckAlive(); +__declspec(dllexport) int __cdecl usbCheckSecurityNew(int i); +__declspec(dllexport) int __cdecl usbCoinGet(int i); +__declspec(dllexport) int __cdecl usbCoinMode(int i); +__declspec(dllexport) int __cdecl usbEnd(); +__declspec(dllexport) int __cdecl usbFirmResult(); +__declspec(dllexport) int __cdecl usbGetKEYID(unsigned char *a, int i); +__declspec(dllexport) int __cdecl usbGetSecurity(int i, unsigned char *a); +__declspec(dllexport) int __cdecl usbLamp(int32_t lamp_bits); +__declspec(dllexport) int __cdecl usbPadRead(unsigned long *pad_bits); +__declspec(dllexport) int __cdecl usbPadReadLast(uint8_t *a1); +__declspec(dllexport) int __cdecl usbSecurityInit(); +__declspec(dllexport) int __cdecl usbSecurityInitDone(); +__declspec(dllexport) int __cdecl usbSecuritySearch(); +__declspec(dllexport) int __cdecl usbSecuritySearchDone(); +__declspec(dllexport) int __cdecl usbSecuritySelect(int i); +__declspec(dllexport) int __cdecl usbSecuritySelectDone(); +__declspec(dllexport) int __cdecl usbSetExtIo(int i); +__declspec(dllexport) int __cdecl usbStart(int i); +__declspec(dllexport) int __cdecl usbWdtReset(); +__declspec(dllexport) int __cdecl usbWdtStart(int i); +__declspec(dllexport) int __cdecl usbWdtStartDone(); +#if POPN15_FORMAT == 1 +} +#endif + +#endif //EZUSB_UPC_EZUSB_H \ No newline at end of file diff --git a/ezusb/src/lib/hid.lib b/ezusb/src/lib/hid.lib new file mode 100644 index 0000000000000000000000000000000000000000..2b5e74965cbf4bb0102db96c33fd7c35d66e8329 GIT binary patch literal 12158 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 LpqalH_^7`C`XVos literal 0 HcmV?d00001