Reinitialize gamepads command and fix EVDEV going bonkers on gamepad suddenly disconnecting

This commit is contained in:
Ilari Liusvaara 2014-11-17 20:12:20 +02:00
parent c68048d029
commit 5ddf119ef0
9 changed files with 71 additions and 31 deletions

View file

@ -32,12 +32,6 @@ void joystick_driver_init() throw();
* - Implemented by the joystick plugin.
*/
void joystick_driver_quit() throw();
/**
* This thread becomes the joystick polling thread.
*
* - Called in joystick polling thread.
*/
void joystick_driver_thread_fn() throw();
/**
* Signal the joystick thread to quit.
*/

View file

@ -127,6 +127,7 @@ public:
void set_axismode_cb(std::function<void(unsigned jnum, unsigned num, int mode, double tolerance)> fn);
void set_newitem_cb(std::function<void(unsigned jnum, unsigned num, int type)> fn);
std::string get_summary();
void offline_all();
private:
set(const set&);
set& operator=(const set&);

View file

@ -3,6 +3,7 @@
namespace
{
threads::thread* joystick_thread_handle;
void dummy_init() throw() {}
void dummy_quit() throw() {}
void dummy_thread_fn() throw() {}
@ -16,6 +17,12 @@ namespace
.signal = dummy_signal,
.name = dummy_name
};
void* joystick_thread(int _args)
{
driver.thread_fn();
return NULL;
}
}
joystick_driver::joystick_driver(_joystick_driver drv)
@ -27,19 +34,17 @@ void joystick_driver_init() throw()
{
lsnes_gamepads_init();
driver.init();
joystick_thread_handle = new threads::thread(joystick_thread, 6);
}
void joystick_driver_quit() throw()
{
driver.quit();
joystick_thread_handle->join();
joystick_thread_handle = NULL;
lsnes_gamepads_deinit();
}
void joystick_driver_thread_fn() throw()
{
driver.thread_fn();
}
void joystick_driver_signal() throw()
{
driver.signal();

View file

@ -1,5 +1,6 @@
#include "core/command.hpp"
#include "core/instance.hpp"
#include "core/joystickapi.hpp"
#include "core/keymapper.hpp"
#include "core/memorymanip.hpp"
#include "core/messages.hpp"
@ -104,4 +105,14 @@ namespace
messages << lsnes_gamepads.get_summary() << std::endl;
messages << "--------------------------------------------" << std::endl;
});
command::fnptr<> reset_joysticks(lsnes_cmds, "reset-gamepads", "Reset gamepads",
"Syntax: reset-gamepads\nResets gamepads.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
joystick_driver_quit();
lsnes_gamepads.offline_all(); //Not supposed to have online gamepads.
joystick_driver_init();
messages << "Reset gamepads" << std::endl;
});
}

View file

@ -724,6 +724,15 @@ unsigned set::add(const std::string& name)
}
}
void set::offline_all()
{
for(size_t i = 0; i < _gamepads.size(); i++) {
if(_gamepads[i]->online()) {
_gamepads[i]->set_online(false);
}
}
}
void set::set_axis_cb(std::function<void(unsigned jnum, unsigned num, int16_t val)> fn)
{
threads::alock h(mlock);

View file

@ -169,22 +169,24 @@ namespace
std::map<int, unsigned> gamepad_map;
bool read_one_input_event(int fd)
int read_one_input_event(int fd)
{
struct input_event ev;
int r = read(fd, &ev, sizeof(ev));
if(r < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK))
return false;
return 0;
if(r < 0) {
if(errno == ENODEV)
return -1; //Disconnected.
messages << "Error reading from joystick (fd=" << fd << "): " << strerror(errno)
<< std::endl;
return false;
return 0;
}
if(ev.type == EV_KEY)
lsnes_gamepads[gamepad_map[fd]].report_button(ev.code, ev.value != 0);
if(ev.type == EV_ABS)
lsnes_gamepads[gamepad_map[fd]].report_axis(ev.code, ev.value);
return true;
return 1;
}
bool probe_joystick(int fd, const std::string& filename)
@ -283,6 +285,8 @@ namespace
struct _joystick_driver drv = {
.init = []() -> void {
quit_signaled = false;
quit_ack = false;
probe_all_joysticks();
quit_ack = quit_signaled = false;
},
@ -309,10 +313,35 @@ namespace
int r = select(limit, &rfds, NULL, NULL, &tv);
if(r <= 0)
continue;
std::set<int> cleanup;
for(auto fd : gamepad_map)
if(FD_ISSET(fd.first, &rfds))
while(read_one_input_event(fd.first));
if(FD_ISSET(fd.first, &rfds)) {
while(true) {
int r = read_one_input_event(fd.first);
if(!r)
break;
if(r < 0) {
cleanup.insert(fd.first);
break;
}
}
}
for(auto i : cleanup) {
unsigned jid = gamepad_map[i];
close(i);
gamepad_map.erase(i);
lsnes_gamepads[jid].set_online(false);
messages << "Gamepad #" << jid << "[" << lsnes_gamepads[jid].name()
<< "] disconnected." << std::endl;
}
}
//Get rid of joystick handles.
for(auto fd : gamepad_map) {
close(fd.first);
lsnes_gamepads[fd.second].set_online(false);
}
gamepad_map.clear();
quit_ack = true;
},
.signal = []() -> void {

View file

@ -38,6 +38,8 @@ namespace
struct _joystick_driver drv = {
.init = []() -> void {
quit_signaled = false;
quit_ack = false;
int jcnt = SDL_SYS_JoystickInit();
if(jcnt < 0)
return;

View file

@ -34,6 +34,8 @@ namespace
struct _joystick_driver drv = {
.init = []() -> void {
quit_signaled = false;
quit_ack = false;
unsigned max_joysticks = joyGetNumDevs();
if(!max_joysticks)
return; //No joystick support.

View file

@ -67,18 +67,11 @@ namespace
volatile bool modal_dialog_active;
threads::lock ui_mutex;
threads::cv ui_condition;
threads::thread* joystick_thread_handle;
bool if_update_messages = false;
bool if_update_screen = false;
bool if_update_status = false;
threads::lock if_mutex;
void* joystick_thread(int _args)
{
joystick_driver_thread_fn();
return NULL;
}
struct uiserv_event : public wxEvent
{
uiserv_event(int code)
@ -516,12 +509,10 @@ bool lsnes_app::OnInit()
if(settings_mode) {
//We got to boot this up quite a bit to get the joystick driver working.
//In practicular, we need joystick thread and emulator thread in pause.
joystick_thread_handle = new threads::thread(joystick_thread, 6);
threads::thread* dummy_loop = new threads::thread(eloop_helper, 8);
display_settings_dialog(NULL, lsnes_instance, NULL);
platform::exit_dummy_event_loop();
joystick_driver_signal();
joystick_thread_handle->join();
joystick_driver_quit();
dummy_loop->join();
save_configuration();
return false;
@ -529,8 +520,6 @@ bool lsnes_app::OnInit()
init_lua();
lsnes_instance.mdumper->set_output(&messages.getstream());
joystick_thread_handle = new threads::thread(joystick_thread, 7);
msg_window = new wxwin_messages(lsnes_instance);
msg_window->Show();
@ -593,8 +582,6 @@ int lsnes_app::OnExit()
save_configuration();
quit_lua();
lsnes_instance.mlogic->release_memory();
joystick_driver_signal();
joystick_thread_handle->join();
platform::quit();
lsnes_instance.buttons->cleanup();
cleanup_keymapper();