From 4cb7d58d53dc7e8750fa02e2121e1386f67b9c87 Mon Sep 17 00:00:00 2001 From: TomW Date: Sun, 8 Jun 2014 13:45:26 +0100 Subject: [PATCH] Added joystick emulation --- src/Makefile.mingw | 4 +- src/gameport.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ src/gameport.h | 1 + src/model.c | 2 + src/pc.c | 3 + src/plat-joystick.h | 19 +++++++ src/win-joystick.cc | 130 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 src/gameport.c create mode 100644 src/gameport.h create mode 100644 src/plat-joystick.h create mode 100644 src/win-joystick.cc diff --git a/src/Makefile.mingw b/src/Makefile.mingw index e7211f2..68c2237 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -4,7 +4,7 @@ CC = gcc.exe WINDRES = windres.exe CFLAGS = -O3 -march=i686 -fomit-frame-pointer OBJ = 386.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \ - config.o cpu.o dac.o device.o dma.o fdc.o \ + config.o cpu.o dac.o device.o dma.o fdc.o gameport.o \ headland.o i430vx.o ide.o io.o jim.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o \ mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \ @@ -18,7 +18,7 @@ OBJ = 386.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \ vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o vid_pcjr.o vid_s3.o \ vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o vid_svga_render.o \ vid_tandy.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o \ - vid_voodoo.o video.o wd76c10.o win.o win-d3d.o win-d3d-fs.o win-ddraw.o win-ddraw-fs.o win-keyboard.o win-midi.o \ + vid_voodoo.o video.o wd76c10.o win.o win-d3d.o win-d3d-fs.o win-ddraw.o win-ddraw-fs.o win-joystick.o win-keyboard.o win-midi.o \ win-mouse.o win-timer.o win-video.o x86seg.o x87.o xtide.o pc.res FMOBJ = dbopl.o SIDOBJ = convolve.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o diff --git a/src/gameport.c b/src/gameport.c new file mode 100644 index 0000000..dc45ec5 --- /dev/null +++ b/src/gameport.c @@ -0,0 +1,136 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "plat-joystick.h" +#include "timer.h" + +#include "gameport.h" + +typedef struct gameport_axis_t +{ + int count; + int axis_nr; + struct gameport_t *gameport; +} gameport_axis_t; + +typedef struct gameport_t +{ + uint8_t state; + + gameport_axis_t axis[4]; +} gameport_t; + +static int gameport_time(int axis) +{ + axis += 32768; + axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 11) / 1000; + return TIMER_USEC * (axis + 24); /*max = 11.115 ms*/ +} + +void gameport_write(uint16_t addr, uint8_t val, void *p) +{ + gameport_t *gameport = (gameport_t *)p; + + gameport->state |= 0x0f; +// pclog("gameport_write : joysticks_present=%i\n", joysticks_present); + if (joysticks_present) + { + gameport->axis[0].count = gameport_time(joystick_state[0].x); + gameport->axis[1].count = gameport_time(joystick_state[0].y); +// pclog("gameport_write: axis[0]=%i,%i axis[1]=%i,%i\n", joystick_state[0].x, gameport->axis[0].count, joystick_state[0].y, gameport->axis[1].count); + } + if (joysticks_present >= 2) + { + gameport->axis[2].count = gameport_time(joystick_state[1].x); + gameport->axis[3].count = gameport_time(joystick_state[1].y); +// pclog("gameport_write: axis[2]=%i,%i axis[3]=%i,%i\n", joystick_state[1].x, gameport->axis[2].count, joystick_state[1].y, gameport->axis[3].count); + } +} + +uint8_t gameport_read(uint16_t addr, void *p) +{ + gameport_t *gameport = (gameport_t *)p; + uint8_t ret; + + ret = gameport->state | 0xf0; + + if (joysticks_present) + { + if (joystick_state[0].b[0]) + ret &= ~0x10; + if (joystick_state[0].b[1]) + ret &= ~0x20; + if (joystick_state[0].b[2]) + ret &= ~0x40; + if (joystick_state[0].b[3]) + ret &= ~0x80; + } + if (joysticks_present >= 2) + { + if (joystick_state[1].b[0]) + ret &= ~0x40; + if (joystick_state[1].b[1]) + ret &= ~0x80; + } + +// pclog("gameport_read: ret=%02x %08x:%08x\n", ret, cs, pc); + return ret; +} + +void gameport_timer_over(void *p) +{ + gameport_axis_t *axis = (gameport_axis_t *)p; + gameport_t *gameport = axis->gameport; + + gameport->state &= ~(1 << axis->axis_nr); + axis->count = 0; + +// pclog("gameport_timer_over : axis_nr=%i\n", axis->axis_nr); +} + +void *gameport_init() +{ + gameport_t *gameport = malloc(sizeof(gameport_t)); + + memset(gameport, 0, sizeof(gameport_t)); + + gameport->axis[0].gameport = gameport; + gameport->axis[1].gameport = gameport; + gameport->axis[2].gameport = gameport; + gameport->axis[3].gameport = gameport; + + gameport->axis[0].axis_nr = 0; + gameport->axis[1].axis_nr = 1; + gameport->axis[2].axis_nr = 2; + gameport->axis[3].axis_nr = 3; + + timer_add(gameport_timer_over, &gameport->axis[0].count, &gameport->axis[0].count, &gameport->axis[0]); + timer_add(gameport_timer_over, &gameport->axis[1].count, &gameport->axis[1].count, &gameport->axis[1]); + timer_add(gameport_timer_over, &gameport->axis[2].count, &gameport->axis[2].count, &gameport->axis[2]); + timer_add(gameport_timer_over, &gameport->axis[3].count, &gameport->axis[3].count, &gameport->axis[3]); + + io_sethandler(0x0200, 0x0008, gameport_read, NULL, NULL, gameport_write, NULL, NULL, gameport); + + return gameport; +} + +void gameport_close(void *p) +{ + gameport_t *gameport = (gameport_t *)p; + + free(gameport); +} + +device_t gameport_device = +{ + "Game port", + 0, + gameport_init, + gameport_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/gameport.h b/src/gameport.h new file mode 100644 index 0000000..6884490 --- /dev/null +++ b/src/gameport.h @@ -0,0 +1 @@ +extern device_t gameport_device; diff --git a/src/model.c b/src/model.c index 8d94136..28cddb5 100644 --- a/src/model.c +++ b/src/model.c @@ -9,6 +9,7 @@ #include "device.h" #include "dma.h" #include "fdc.h" +#include "gameport.h" #include "headland.h" #include "i430vx.h" #include "ide.h" @@ -122,6 +123,7 @@ void common_init() pit_init(); serial1_init(0x3f8, 4); serial2_init(0x2f8, 3); + device_add(&gameport_device); } void xt_init() diff --git a/src/pc.c b/src/pc.c index 5fad32c..9e4ed7e 100644 --- a/src/pc.c +++ b/src/pc.c @@ -20,6 +20,7 @@ #include "nvr.h" #include "pic.h" #include "pit.h" +#include "plat-joystick.h" #include "plat-mouse.h" #include "serial.h" #include "sound.h" @@ -196,6 +197,7 @@ void initpc() keyboard_init(); mouse_init(); + joystick_init(); loadconfig(); pclog("Config loaded\n"); @@ -326,6 +328,7 @@ void runpc() keyboard_process(); // checkkeys(); pollmouse(); + poll_joystick(); endblit(); framecountx++; diff --git a/src/plat-joystick.h b/src/plat-joystick.h new file mode 100644 index 0000000..efe87ba --- /dev/null +++ b/src/plat-joystick.h @@ -0,0 +1,19 @@ +#ifdef __cplusplus +extern "C" { +#endif + void joystick_init(); + void joystick_close(); + void poll_joystick(); + + typedef struct joystick_t + { + int x, y; + int b[4]; + } joystick_t; + + extern joystick_t joystick_state[2]; + extern int joysticks_present; +#ifdef __cplusplus +} +#endif + diff --git a/src/win-joystick.cc b/src/win-joystick.cc new file mode 100644 index 0000000..65962cd --- /dev/null +++ b/src/win-joystick.cc @@ -0,0 +1,130 @@ +#include +#include "plat-joystick.h" +#include "plat-dinput.h" +#include "win.h" + +extern "C" int video_fullscreen; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void joystick_init(); +extern "C" void joystick_close(); +extern "C" void poll_joystick(); + +joystick_t joystick_state[2]; + +static LPDIRECTINPUTDEVICE2 lpdi_joystick[2] = {NULL, NULL}; + +int joysticks_present = 0; +static GUID joystick_guids[2]; + +static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, LPVOID data) +{ + if (joysticks_present >= 2) + return DIENUM_STOP; + + pclog("joystick_enum_callback : found joystick %i : %s\n", joysticks_present, lpddi->tszProductName); + + joystick_guids[joysticks_present++] = lpddi->guidInstance; + + if (joysticks_present >= 2) + return DIENUM_STOP; + + return DIENUM_CONTINUE; +} + +void joystick_init() +{ + int c; + + atexit(joystick_close); + + joysticks_present = 0; + + if (FAILED(lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, joystick_enum_callback, NULL, DIEDFL_ATTACHEDONLY))) + fatal("joystick_init : EnumDevices failed\n"); + + pclog("joystick_init: joysticks_present=%i\n", joysticks_present); + + for (c = 0; c < joysticks_present; c++) + { + LPDIRECTINPUTDEVICE lpdi_joystick_temp = NULL; + DIPROPRANGE joy_axis_range; + + if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) + fatal("joystick_init : CreateDevice failed\n"); + if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice2, (void **)&lpdi_joystick[c]))) + fatal("joystick_init : CreateDevice failed\n"); + lpdi_joystick_temp->Release(); + if (FAILED(lpdi_joystick[c]->SetCooperativeLevel(ghwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + fatal("joystick_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_joystick[c]->SetDataFormat(&c_dfDIJoystick))) + fatal("joystick_init : SetDataFormat failed\n"); + + joy_axis_range.lMin = -32768; + joy_axis_range.lMax = 32767; + joy_axis_range.diph.dwSize = sizeof(DIPROPRANGE); + joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + joy_axis_range.diph.dwObj = DIJOFS_X; + joy_axis_range.diph.dwHow = DIPH_BYOFFSET; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + + joy_axis_range.lMin = -32768; + joy_axis_range.lMax = 32767; + joy_axis_range.diph.dwSize = sizeof(DIPROPRANGE); + joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + joy_axis_range.diph.dwObj = DIJOFS_Y; + joy_axis_range.diph.dwHow = DIPH_BYOFFSET; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + + if (FAILED(lpdi_joystick[c]->Acquire())) + fatal("joystick_init : Acquire failed\n"); + } +} + +void joystick_close() +{ + if (lpdi_joystick[1]) + { + lpdi_joystick[1]->Release(); + lpdi_joystick[1] = NULL; + } + if (lpdi_joystick[0]) + { + lpdi_joystick[0]->Release(); + lpdi_joystick[0] = NULL; + } +} + +void poll_joystick() +{ + int c; + + for (c = 0; c < joysticks_present; c++) + { + DIJOYSTATE joystate; + + if (FAILED(lpdi_joystick[c]->Poll())) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + } + if (FAILED(lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate))) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate); + } + + joystick_state[c].x = joystate.lX; + joystick_state[c].y = joystate.lY; + joystick_state[c].b[0] = joystate.rgbButtons[0] & 0x80; + joystick_state[c].b[1] = joystate.rgbButtons[1] & 0x80; + joystick_state[c].b[2] = joystate.rgbButtons[2] & 0x80; + joystick_state[c].b[3] = joystate.rgbButtons[3] & 0x80; + + pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); + } +} +