diff -Nur a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp --- a/core/hw/maple/maple_cfg.cpp 2016-03-18 23:11:34.099340091 -0300 +++ b/core/hw/maple/maple_cfg.cpp 2016-03-18 23:12:24.396511206 -0300 @@ -21,6 +21,7 @@ ImageUpdate(data); */ void UpdateInputState(u32 port); +void UpdateVibration(u32 port, u32 value); extern u16 kcode[4]; extern u32 vks[4]; @@ -41,6 +42,11 @@ this->dev=dev; } + void SetVibration(u32 value) + { + UpdateVibration(dev->bus_id, value); + } + void GetInput(PlainJoystickState* pjs) { UpdateInputState(dev->bus_id); diff -Nur a/core/hw/maple/maple_cfg.h b/core/hw/maple/maple_cfg.h --- a/core/hw/maple/maple_cfg.h 2016-03-18 23:11:34.099340091 -0300 +++ b/core/hw/maple/maple_cfg.h 2016-03-18 23:12:24.396511206 -0300 @@ -57,6 +57,7 @@ struct IMapleConfigMap { + virtual void SetVibration(u32 value) = 0; virtual void GetInput(PlainJoystickState* pjs)=0; virtual void SetImage(void* img)=0; virtual ~IMapleConfigMap() {} diff -Nur a/core/hw/maple/maple_devs.cpp b/core/hw/maple/maple_devs.cpp --- a/core/hw/maple/maple_devs.cpp 2016-03-18 23:11:34.099340091 -0300 +++ b/core/hw/maple/maple_devs.cpp 2016-03-18 23:12:24.396511206 -0300 @@ -22,6 +22,7 @@ const char* maple_sega_dreameye_name_1 = "Dreamcast Camera Flash Devic"; const char* maple_sega_dreameye_name_2 = "Dreamcast Camera Flash LDevic"; const char* maple_sega_mic_name = "MicDevice for Dreameye"; +const char* maple_sega_purupuru_name = "Puru Puru Pack"; const char* maple_sega_brand = "Produced By or Under License From SEGA ENTERPRISES,LTD."; @@ -844,6 +845,98 @@ } }; + +struct maple_sega_purupuru : maple_base +{ + u16 AST, AST_ms; + u32 VIBSET; + + virtual u32 dma(u32 cmd) + { + switch (cmd) + { + case MDC_DeviceRequest: + //caps + //4 + w32(MFID_8_Vibration); + + //struct data + //3*4 + w32(0x00000101); + w32(0); + w32(0); + + //1 area code + w8(0xFF); + + //1 direction + w8(0); + + //30 + wstr(maple_sega_purupuru_name, 30); + + //60 + wstr(maple_sega_brand, 60); + + //2 + w16(0x00C8); + + //2 + w16(0x0640); + + return MDRS_DeviceStatus; + + //get last vibration + case MDCF_GetCondition: + + w32(MFID_8_Vibration); + + w32(VIBSET); + + return MDRS_DataTransfer; + + case MDCF_GetMediaInfo: + + w32(MFID_8_Vibration); + + // PuruPuru vib specs + w32(0x3B07E010); + + return MDRS_DataTransfer; + + case MDCF_BlockRead: + + w32(MFID_8_Vibration); + w32(0); + + w16(2); + w16(AST); + + return MDRS_DataTransfer; + + case MDCF_BlockWrite: + + //Auto-stop time + AST = dma_buffer_in[10]; + AST_ms = AST * 250 + 250; + + return MDRS_DeviceReply; + + case MDCF_SetCondition: + + VIBSET = *(u32*)&dma_buffer_in[4]; + //Do the rumble thing! + config->SetVibration(VIBSET); + + return MDRS_DeviceReply; + + default: + //printf("UNKOWN MAPLE COMMAND %d\n",cmd); + return MDRE_UnknownFunction; + } + } +}; + char EEPROM[0x100]; bool EEPROM_loaded = false; @@ -1300,6 +1393,11 @@ rv = new maple_sega_vmu(); break; + case MDT_PurupuruPack: + rv = new maple_sega_purupuru(); + break; + + case MDT_NaomiJamma: rv = new maple_naomi_jamma(); diff -Nur a/core/hw/maple/maple_devs.h b/core/hw/maple/maple_devs.h --- a/core/hw/maple/maple_devs.h 2016-03-18 23:11:34.099340091 -0300 +++ b/core/hw/maple/maple_devs.h 2016-03-18 23:12:24.396511206 -0300 @@ -6,6 +6,7 @@ MDT_SegaController, MDT_SegaVMU, MDT_Microphone, + MDT_PurupuruPack, MDT_NaomiJamma, diff -Nur a/core/linux-dist/evdev.cpp b/core/linux-dist/evdev.cpp --- a/core/linux-dist/evdev.cpp 2016-03-18 23:11:34.113340136 -0300 +++ b/core/linux-dist/evdev.cpp 2016-03-18 23:12:24.397511209 -0300 @@ -102,6 +102,7 @@ this->data_y.init(this->fd, this->mapping->Axis_Analog_Y, this->mapping->Axis_Analog_Y_Inverted); this->data_trigger_left.init(this->fd, this->mapping->Axis_Trigger_Left, this->mapping->Axis_Trigger_Left_Inverted); this->data_trigger_right.init(this->fd, this->mapping->Axis_Trigger_Right, this->mapping->Axis_Trigger_Right_Inverted); + this->rumble_effect_id = -1; } std::map loaded_mappings; @@ -202,7 +203,7 @@ printf("evdev: Trying to open device at '%s'\n", device); - int fd = open(device, O_RDONLY); + int fd = open(device, O_RDWR); if (fd >= 0) { @@ -446,5 +447,43 @@ } } } + + void input_evdev_rumble(EvdevController* controller, u16 pow_strong, u16 pow_weak) + { + if (controller->fd < 0 || controller->rumble_effect_id == -2) + { + // Either the controller is not used or previous rumble effect failed + printf("RUMBLE: %s\n", "Skipped!"); + return; + } + printf("RUMBLE: %u / %u (%d)\n", pow_strong, pow_weak, controller->rumble_effect_id); + struct ff_effect effect; + effect.type = FF_RUMBLE; + effect.id = controller->rumble_effect_id; + effect.u.rumble.strong_magnitude = pow_strong; + effect.u.rumble.weak_magnitude = pow_weak; + effect.replay.length = 0; + effect.replay.delay = 0; + if (ioctl(controller->fd, EVIOCSFF, &effect) == -1) + { + perror("evdev: Force feedback error"); + controller->rumble_effect_id = -2; + } + else + { + controller->rumble_effect_id = effect.id; + + // Let's play the effect + input_event play; + play.type = EV_FF; + play.code = effect.id; + play.value = 1; + if (write(controller->fd, (const void*) &play, sizeof(play)) == -1) + { + perror("evdev: Force feedback error"); + controller->rumble_effect_id = -2; + } + } + } #endif diff -Nur a/core/linux-dist/evdev.h b/core/linux-dist/evdev.h --- a/core/linux-dist/evdev.h 2016-03-18 23:11:34.113340136 -0300 +++ b/core/linux-dist/evdev.h 2016-03-18 23:12:24.397511209 -0300 @@ -54,6 +54,7 @@ EvdevAxisData data_y; EvdevAxisData data_trigger_left; EvdevAxisData data_trigger_right; + int rumble_effect_id; void init(); }; @@ -72,3 +73,4 @@ extern int input_evdev_init(EvdevController* controller, const char* device, const char* mapping_fname); extern bool input_evdev_handle(EvdevController* controller, u32 port); +extern void input_evdev_rumble(EvdevController* controller, u16 pow_strong, u16 pow_weak); diff -Nur a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp --- a/core/linux-dist/main.cpp 2016-03-18 23:11:34.113340136 -0300 +++ b/core/linux-dist/main.cpp 2016-03-18 23:12:24.397511209 -0300 @@ -191,6 +191,30 @@ #endif } +void UpdateVibration(u32 port, u32 value) +{ + #if defined(USE_EVDEV) + const u8 freq_l = 0x16; + //const u8 freq_h = 0x31; + + u8 POW_POS = (value >> 8) & 0x3; + u8 POW_NEG = (value >> 12) & 0x3; + u8 FREQ = (value >> 16) & 0xFF; + + double pow = (POW_POS + POW_NEG) / 7.0; + double pow_l = pow * (0x3B - FREQ) / 17.0; + double pow_r = pow * (FREQ / (double)freq_l); + + if (pow_l > 1.0) pow_l = 1.0; + if (pow_r > 1.0) pow_r = 1.0; + + u16 pow_strong = (u16)(65535 * pow_l); + u16 pow_weak = (u16)(65535 * pow_r); + + input_evdev_rumble(&evdev_controllers[port], pow_strong, pow_weak); + #endif +} + void os_DoEvents() { #if defined(SUPPORT_X11) diff -Nur a/core/nacl/nacl.cpp b/core/nacl/nacl.cpp --- a/core/nacl/nacl.cpp 2016-03-18 23:11:34.114340140 -0300 +++ b/core/nacl/nacl.cpp 2016-03-18 23:12:24.397511209 -0300 @@ -257,6 +257,10 @@ } +void UpdateVibration(u32 port, u32 value) { + +} + void os_CreateWindow() { } diff -Nur a/core/windows/winmain.cpp b/core/windows/winmain.cpp --- a/core/windows/winmain.cpp 2016-03-18 23:11:34.119340156 -0300 +++ b/core/windows/winmain.cpp 2016-03-18 23:12:24.399511217 -0300 @@ -5,6 +5,8 @@ #define _WIN32_WINNT 0x0500 #include +#include +#pragma comment(lib, "XInput9_1_0.lib") PCHAR* CommandLineToArgvA( @@ -105,7 +107,7 @@ bool VramLockedWrite(u8* address); bool ngen_Rewrite(unat& addr,unat retadr,unat acc); bool BM_LockedWrite(u8* address); - +void UpdateController(u32 port); LONG ExeptionHandler(EXCEPTION_POINTERS *ExceptionInfo) { @@ -235,6 +237,8 @@ if (GetAsyncKeyState(VK_RIGHT)) kcode[port]&=~key_CONT_DPAD_RIGHT; + UpdateController(port); + if (GetAsyncKeyState(VK_F1)) settings.pvr.ta_skip = 100; @@ -245,7 +249,66 @@ DiscSwap(); } +void UpdateController(u32 port) + { + XINPUT_STATE state; + + if (XInputGetState(port, &state) == 0) + { + WORD xbutton = state.Gamepad.wButtons; + + if (xbutton & XINPUT_GAMEPAD_A) + kcode[port] &= ~key_CONT_A; + if (xbutton & XINPUT_GAMEPAD_B) + kcode[port] &= ~key_CONT_B; + if (xbutton & XINPUT_GAMEPAD_Y) + kcode[port] &= ~key_CONT_Y; + if (xbutton & XINPUT_GAMEPAD_X) + kcode[port] &= ~key_CONT_X; + + if (xbutton & XINPUT_GAMEPAD_START) + kcode[port] &= ~key_CONT_START; + + if (xbutton & XINPUT_GAMEPAD_DPAD_UP) + kcode[port] &= ~key_CONT_DPAD_UP; + if (xbutton & XINPUT_GAMEPAD_DPAD_DOWN) + kcode[port] &= ~key_CONT_DPAD_DOWN; + if (xbutton & XINPUT_GAMEPAD_DPAD_LEFT) + kcode[port] &= ~key_CONT_DPAD_LEFT; + if (xbutton & XINPUT_GAMEPAD_DPAD_RIGHT) + kcode[port] &= ~key_CONT_DPAD_RIGHT; + + lt[port] |= state.Gamepad.bLeftTrigger; + rt[port] |= state.Gamepad.bRightTrigger; + + joyx[port] |= state.Gamepad.sThumbLX / 257; + joyy[port] |= -state.Gamepad.sThumbLY / 257; + } + } +void UpdateVibration(u32 port, u32 value) +{ + const u8 freq_l = 0x16; + //const u8 freq_h = 0x31; + + u8 POW_POS = (value >> 8) & 0x3; + u8 POW_NEG = (value >> 12) & 0x3; + u8 FREQ = (value >> 16) & 0xFF; + + XINPUT_VIBRATION vib; + + double pow = (POW_POS + POW_NEG) / 7.0; + double pow_l = pow * (0x3B - FREQ) / 17.0; + double pow_r = pow * (FREQ - 0x07) / 15.0; + + if (pow_l > 1.0) pow_l = 1.0; + if (pow_r > 1.0) pow_r = 1.0; + + vib.wLeftMotorSpeed = (u16)(65535 * pow_l); + vib.wRightMotorSpeed = (u16)(65535 * pow_r); + + XInputSetState(port, &vib); +} LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { diff -Nur a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp --- a/shell/android/jni/src/Android.cpp 2016-03-18 23:11:34.145340240 -0300 +++ b/shell/android/jni/src/Android.cpp 2016-03-18 23:12:24.399511217 -0300 @@ -231,6 +231,11 @@ // @@@ Nothing here yet } +void UpdateVibration(u32 port, u32 value) +{ + +} + void *libPvr_GetRenderTarget() { // No X11 window in Android diff -Nur a/shell/apple/emulator-ios/emulator/ios_main.mm b/shell/apple/emulator-ios/emulator/ios_main.mm --- a/shell/apple/emulator-ios/emulator/ios_main.mm 2016-03-18 23:11:34.192340393 -0300 +++ b/shell/apple/emulator-ios/emulator/ios_main.mm 2016-03-18 23:12:24.400511220 -0300 @@ -106,6 +106,10 @@ } +void UpdateVibration(u32 port, u32 value) { + +} + void get_mic_data(u8* ) { } diff -Nur a/shell/apple/emulator-osx/emulator-osx/osx-main.mm b/shell/apple/emulator-osx/emulator-osx/osx-main.mm --- a/shell/apple/emulator-osx/emulator-osx/osx-main.mm 2016-03-18 23:11:34.194340399 -0300 +++ b/shell/apple/emulator-osx/emulator-osx/osx-main.mm 2016-03-18 23:12:24.401511224 -0300 @@ -59,6 +59,10 @@ } +void UpdateVibration(u32 port, u32 value) { + +} + void os_CreateWindow() { }