Cleaned up subsystem init code, split it into classes (thread cleanup in daemon currently broken)

This commit is contained in:
Ingo Ruhnke 2011-03-25 18:02:21 +01:00
parent 1e1843e41e
commit 1270ec69f6
14 changed files with 569 additions and 400 deletions

1
.gitignore vendored
View file

@ -18,3 +18,4 @@ test/ini_parser_test
test/usb_read_thread_test
test/usb_system_test
xboxdrv
incoming/

32
TODO
View file

@ -57,6 +57,10 @@ Stuff to do before 0.8.0 release:
Checklist
=========
* make dbus optional
* check force feedback
* check output when --silent not given
* check clean shutdown
@ -86,20 +90,21 @@ Checklist
xboxdrv: src/usb_controller.cpp:218: void USBController::on_read_data(libusb_transfer*): Assertion `ret == LIBUSB_SUCCESS' failed.
Aborted
* exceptions in glib main loop might be dangerous
* exceptions in glib main loop might be dangerous and not really do what is intended
* invert y axis on --evdev
* move sigint/sigterm handling out of main.cpp and into xboxdrv_daemon.cpp (needs to use gmain_quit())
* LED do currently not get down on controller quit
* move LED setting into ControllerThread or somewhere else, not at controller creation time
* check that threads are cleaned up in daemon
Stuff to do before 0.7.4 release:
=================================
* add double-click button, in the same wayne as hold-button
* add --controller 4 or --controller-count 4 or something like that
* add special LED status set switches the LED with the given config
* invert y axis on --evdev
if (opts.priority == Options::kPriorityRealtime)
{
@ -132,6 +137,12 @@ Stuff to do before 0.7.4 release:
}
}
* add double-click button, in the same wayne as hold-button
* add --controller 4 or --controller-count 4 or something like that
* add special LED status set switches the LED with the given config
* export build-in config files, both as text and as directory, so that users can browse them
* deadzone:MIN:MAX:SMOOTH is broken (fixed)
@ -204,7 +215,7 @@ Here KEY_B is the key you want to send and KEY_A is a random other key
that you don't need. It's a hack as mapping both to KEY_B seems to
cause some trouble with automatic key repeat for some reason. Note
that you must not combine this with --trigger-as-zaxis as that will
disable LT and RT
disable LT and RT -> already fixed, check it
* add a "click" filter or something like that, that causes a button to only be clicked, not hold
@ -249,12 +260,7 @@ disable LT and RT
-> hard to avoid, as wireless controllers are only picked up when
active, which they always become later then the wired ones, which
are active by default)
* add libusb-0.1 support back (maybe only in 0.7.4)
-> no, need a full switch
* move sigint/sigterm handling out of main.cpp and into xboxdrv_daemon.cpp (needs to use gmain_quit())
* BTN_A@joystick.1 doesn't work for a single joystick, why? (joystick isn't id=0, why?)
* improve output on which uinput devices are created (even with udev

105
src/dbus_subsystem.cpp Normal file
View file

@ -0,0 +1,105 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dbus_subsystem.hpp"
#include <boost/format.hpp>
#include <dbus/dbus-glib-lowlevel.h>
//#include <dbus/dbus-glib-binding.h>
#include <dbus/dbus.h>
#include <sstream>
#include <stdexcept>
#include "raise_exception.hpp"
#include "xboxdrv_g_controller.hpp"
#include "xboxdrv_g_daemon.hpp"
#include "xboxdrv_daemon_glue.hpp"
#include "xboxdrv_controller_glue.hpp"
DBusSubsystem::DBusSubsystem(const std::string& name) :
m_connection()
{
GError* gerror = NULL;
// this calls automatically sets up connection to the main loop
m_connection = dbus_g_bus_get(DBUS_BUS_SESSION, &gerror);
if (!m_connection)
{
std::ostringstream out;
out << "failed to open connection to bus: " << gerror->message;
g_error_free(gerror);
throw std::runtime_error(out.str());
}
request_name(name);
}
DBusSubsystem::~DBusSubsystem()
{
}
void
DBusSubsystem::request_name(const std::string& name)
{
DBusError error;
dbus_error_init(&error);
// FIXME: replace this with org_freedesktop_DBus_request_name()
int ret = dbus_bus_request_name(dbus_g_connection_get_connection(m_connection),
name.c_str(),
DBUS_NAME_FLAG_REPLACE_EXISTING,
&error);
if (dbus_error_is_set(&error))
{
std::ostringstream out;
out << "failed to get unique dbus name: " << error.message;
dbus_error_free(&error);
throw std::runtime_error(out.str());
}
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
{
raise_exception(std::runtime_error, "failed to become primary owner of dbus name");
}
}
void
DBusSubsystem::register_xboxdrv_daemon(XboxdrvDaemon* c_daemon)
{
// FIXME: should unref() these somewhere
XboxdrvGDaemon* daemon = xboxdrv_g_daemon_new(c_daemon);
dbus_g_object_type_install_info(XBOXDRV_TYPE_G_DAEMON, &dbus_glib_xboxdrv_daemon_object_info);
dbus_g_connection_register_g_object(m_connection, "/org/seul/Xboxdrv/Daemon", G_OBJECT(daemon));
}
void
DBusSubsystem::register_controller_slots(const std::vector<ControllerSlotPtr>& slots)
{
for(std::vector<ControllerSlotPtr>::const_iterator i = slots.begin(); i != slots.end(); ++i)
{
XboxdrvGController* controller = xboxdrv_g_controller_new(i->get());
dbus_g_object_type_install_info(XBOXDRV_TYPE_G_CONTROLLER, &dbus_glib_xboxdrv_controller_object_info);
dbus_g_connection_register_g_object(m_connection,
(boost::format("/org/seul/Xboxdrv/ControllerSlots/%d")
% (i - slots.begin())).str().c_str(),
G_OBJECT(controller));
}
}
/* EOF */

52
src/dbus_subsystem.hpp Normal file
View file

@ -0,0 +1,52 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_DBUS_SUBSYSTEM_HPP
#define HEADER_XBOXDRV_DBUS_SUBSYSTEM_HPP
#include <dbus/dbus-glib.h>
#include <string>
#include <vector>
#include "controller_slot_ptr.hpp"
class XboxdrvDaemon;
class DBusSubsystem
{
private:
DBusGConnection* m_connection;
public:
DBusSubsystem(const std::string& name);
~DBusSubsystem();
void register_xboxdrv_daemon(XboxdrvDaemon* c_daemon);
void register_controller_slots(const std::vector<ControllerSlotPtr>& slots);
private:
void request_name(const std::string& name);
private:
DBusSubsystem(const DBusSubsystem&);
DBusSubsystem& operator=(const DBusSubsystem&);
};
#endif
/* EOF */

237
src/udev_subsystem.cpp Normal file
View file

@ -0,0 +1,237 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "udev_subsystem.hpp"
#include <stdexcept>
#include "raise_exception.hpp"
UdevSubsystem::UdevSubsystem() :
m_udev(),
m_monitor(),
m_process_match_cb()
{
m_udev = udev_new();
if (!m_udev)
{
raise_exception(std::runtime_error, "udev init failure");
}
}
UdevSubsystem::~UdevSubsystem()
{
if (m_monitor)
{
udev_monitor_unref(m_monitor);
}
udev_unref(m_udev);
}
void
UdevSubsystem::set_device_callback(const boost::function<void (udev_device*)>& process_match_cb)
{
assert(process_match_cb);
assert(!m_process_match_cb);
m_process_match_cb = process_match_cb;
// Setup udev monitor and enumerate
m_monitor = udev_monitor_new_from_netlink(m_udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "usb", "usb_device");
udev_monitor_enable_receiving(m_monitor);
// FIXME: won't we get devices twice that have been plugged in at
// this point? once from the enumeration, once from the monitor
enumerate_udev_devices();
GIOChannel* udev_channel = g_io_channel_unix_new(udev_monitor_get_fd(m_monitor));
g_io_add_watch(udev_channel,
static_cast<GIOCondition>(G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP),
&UdevSubsystem::on_udev_data_wrap, this);
g_io_channel_unref(udev_channel);
}
void
UdevSubsystem::enumerate_udev_devices()
{
assert(m_process_match_cb);
// Enumerate over all devices already connected to the computer
struct udev_enumerate* enumerate = udev_enumerate_new(m_udev);
assert(enumerate);
udev_enumerate_add_match_subsystem(enumerate, "usb");
// not available yet: udev_enumerate_add_match_is_initialized(enumerate);
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry* devices;
struct udev_list_entry* dev_list_entry;
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices)
{
// name is path, value is NULL
const char* path = udev_list_entry_get_name(dev_list_entry);
struct udev_device* device = udev_device_new_from_syspath(m_udev, path);
// manually filter for devtype, as udev enumerate can't do it by itself
const char* devtype = udev_device_get_devtype(device);
if (devtype && strcmp(devtype, "usb_device") == 0)
{
m_process_match_cb(device);
}
udev_device_unref(device);
}
udev_enumerate_unref(enumerate);
}
bool
UdevSubsystem::on_udev_data(GIOChannel* channel, GIOCondition condition)
{
if (condition == G_IO_OUT)
{
log_error("data can be written");
}
else if (condition == G_IO_PRI)
{
log_error("data can be read");
}
else if (condition == G_IO_ERR)
{
log_error("data error");
}
else if (condition != G_IO_IN)
{
log_error("unknown condition: " << condition);
}
else
{
log_info("trying to read data from udev");
log_info("trying to read data from udev monitor");
struct udev_device* device = udev_monitor_receive_device(m_monitor);
log_info("got data from udev monitor");
if (!device)
{
// seem to be normal, do we get this when the given device is filtered out?
log_debug("udev device couldn't be read: " << device);
}
else
{
const char* action = udev_device_get_action(device);
if (g_logger.get_log_level() >= Logger::kDebug)
{
print_info(device);
}
if (action && strcmp(action, "add") == 0)
{
m_process_match_cb(device);
}
udev_device_unref(device);
}
}
return true;
}
void
UdevSubsystem::print_info(udev_device* device)
{
log_debug("/---------------------------------------------");
log_debug("devpath: " << udev_device_get_devpath(device));
if (udev_device_get_action(device))
log_debug("action: " << udev_device_get_action(device));
//log_debug("init: " << udev_device_get_is_initialized(device));
if (udev_device_get_subsystem(device))
log_debug("subsystem: " << udev_device_get_subsystem(device));
if (udev_device_get_devtype(device))
log_debug("devtype: " << udev_device_get_devtype(device));
if (udev_device_get_syspath(device))
log_debug("syspath: " << udev_device_get_syspath(device));
if (udev_device_get_sysname(device))
log_debug("sysname: " << udev_device_get_sysname(device));
if (udev_device_get_sysnum(device))
log_debug("sysnum: " << udev_device_get_sysnum(device));
if (udev_device_get_devnode(device))
log_debug("devnode: " << udev_device_get_devnode(device));
if (udev_device_get_driver(device))
log_debug("driver: " << udev_device_get_driver(device));
if (udev_device_get_action(device))
log_debug("action: " << udev_device_get_action(device));
//udev_device_get_sysattr_value(device, "busnum");
//udev_device_get_sysattr_value(device, "devnum");
#if 0
// FIXME: only works with newer versions of libudev
{
log_debug("list: ");
struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
while((it = udev_list_entry_get_next(it)) != 0)
{
log_debug(" "
<< udev_list_entry_get_name(it) << " = "
<< udev_list_entry_get_value(it)
);
}
}
{
log_debug("properties: ");
struct udev_list_entry* it = udev_device_get_properties_list_entry(device);
while((it = udev_list_entry_get_next(it)) != 0)
{
log_debug(" "
<< udev_list_entry_get_name(it) << " = "
<< udev_list_entry_get_value(it)
);
}
}
{
log_debug("devlist: ");
struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
while((it = udev_list_entry_get_next(it)) != 0)
{
log_debug(" "
<< udev_list_entry_get_name(it) << " = "
<< udev_list_entry_get_value(it)
);
}
}
#endif
log_debug("\\----------------------------------------------");
}
/* EOF */

56
src/udev_subsystem.hpp Normal file
View file

@ -0,0 +1,56 @@
/*
** Xbox360 USB Gamepad Userspace Driver
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADER_XBOXDRV_UDEV_SUBSYSTEM_HPP
#define HEADER_XBOXDRV_UDEV_SUBSYSTEM_HPP
#include <boost/function.hpp>
#include <libudev.h>
#include <glib.h>
class UdevSubsystem
{
private:
struct udev* m_udev;
struct udev_monitor* m_monitor;
boost::function<void (udev_device*)> m_process_match_cb;
public:
UdevSubsystem();
~UdevSubsystem();
void set_device_callback(const boost::function<void (udev_device*)>& process_match_cb);
void enumerate_udev_devices();
void print_info(udev_device* device);
private:
bool on_udev_data(GIOChannel* channel, GIOCondition condition);
static gboolean on_udev_data_wrap(GIOChannel* channel, GIOCondition condition, gpointer data) {
return static_cast<UdevSubsystem*>(data)->on_udev_data(channel, condition);
}
private:
UdevSubsystem(const UdevSubsystem&);
UdevSubsystem& operator=(const UdevSubsystem&);
};
#endif
/* EOF */

View file

@ -21,10 +21,30 @@
#include <stdexcept>
#include <boost/format.hpp>
#include "usb_helper.hpp"
#include "options.hpp"
#include "raise_exception.hpp"
#include "usb_gsource.hpp"
#include "usb_helper.hpp"
USBSubsystem::USBSubsystem() :
m_usb_gsource()
{
int ret = libusb_init(NULL);
if (ret != LIBUSB_SUCCESS)
{
raise_exception(std::runtime_error, "libusb_init() failed: " << usb_strerror(ret));
}
m_usb_gsource.reset(new USBGSource);
m_usb_gsource->attach(NULL);
}
USBSubsystem::~USBSubsystem()
{
m_usb_gsource.reset();
libusb_exit(NULL);
}
void
USBSubsystem::find_controller(libusb_device** dev, XPadDevice& dev_type, const Options& opts)
{

View file

@ -20,17 +20,23 @@
#define HEADER_XBOXDRV_USB_SUBSYSTEM_HPP
#include <libusb.h>
#include <boost/scoped_ptr.hpp>
#include "xpad_device.hpp"
class USBGSource;
class Options;
class USBSubsystem
{
private:
boost::scoped_ptr<USBGSource> m_usb_gsource;
public:
USBSubsystem();
~USBSubsystem();
public:
static void find_controller(libusb_device** dev, XPadDevice& dev_type, const Options& opts);
static bool find_controller_by_path(const std::string& busid, const std::string& devid,
libusb_device** xbox_device);

View file

@ -96,8 +96,6 @@ Xbox360Controller::set_led(uint8_t status)
bool
Xbox360Controller::parse(uint8_t* data, int len, XboxGenericMsg* msg_out)
{
log_trace();
if (len == 0)
{
// happens with the Xbox360 controller every now and then, just

View file

@ -204,12 +204,6 @@ Xboxdrv::run_daemon(const Options& opts)
print_copyright();
}
int ret = libusb_init(NULL);
if (ret != LIBUSB_SUCCESS)
{
raise_exception(std::runtime_error, "libusb_init() failed: " << usb_strerror(ret));
}
if (opts.usb_debug)
{
libusb_set_debug(NULL, 3);
@ -254,8 +248,6 @@ Xboxdrv::run_daemon(const Options& opts)
}
}
}
libusb_exit(NULL);
}
void

View file

@ -34,10 +34,9 @@
#include "controller_factory.hpp"
#include "controller_slot.hpp"
#include "controller.hpp"
#include "xboxdrv_g_daemon.hpp"
#include "xboxdrv_g_controller.hpp"
#include "xboxdrv_daemon_glue.hpp"
#include "xboxdrv_controller_glue.hpp"
#include "udev_subsystem.hpp"
#include "dbus_subsystem.hpp"
#include "usb_subsystem.hpp"
XboxdrvDaemon* XboxdrvDaemon::s_current = 0;
@ -98,16 +97,19 @@ bool get_usb_path(udev_device* device, int* bus, int* dev)
XboxdrvDaemon::XboxdrvDaemon(const Options& opts) :
m_opts(opts),
m_udev(0),
m_monitor(0),
m_usb_gsource(),
m_gmain(),
m_controller_slots(),
m_inactive_controllers(),
m_uinput(),
m_gmain()
m_uinput()
{
assert(!s_current);
s_current = this;
g_type_init();
m_gmain = g_main_loop_new(NULL, false);
signal(SIGINT, &XboxdrvDaemon::on_sigint);
signal(SIGTERM, &XboxdrvDaemon::on_sigint);
}
XboxdrvDaemon::~XboxdrvDaemon()
@ -125,8 +127,34 @@ XboxdrvDaemon::~XboxdrvDaemon()
}
}
udev_monitor_unref(m_monitor);
udev_unref(m_udev);
g_main_loop_unref(m_gmain);
}
void
XboxdrvDaemon::run()
{
try
{
create_pid_file();
init_uinput();
USBSubsystem usb_subsystem;
UdevSubsystem udev_subsystem;
udev_subsystem.set_device_callback(boost::bind(&XboxdrvDaemon::process_match, this, _1));
DBusSubsystem dbus_subsystem("org.seul.Xboxdrv");
dbus_subsystem.register_xboxdrv_daemon(this);
dbus_subsystem.register_controller_slots(m_controller_slots);
log_debug("launching into main loop");
g_main_loop_run(m_gmain);
}
catch(const std::exception& err)
{
log_error("fatal exception: " << err.what());
}
}
void
@ -156,6 +184,9 @@ XboxdrvDaemon::cleanup_threads()
void
XboxdrvDaemon::process_match(struct udev_device* device)
{
// FIXME: bad place?!
// FIXME: cleanup_threads();
uint16_t vendor;
uint16_t product;
@ -239,65 +270,6 @@ XboxdrvDaemon::init_uinput()
}
}
void
XboxdrvDaemon::init_udev()
{
assert(!m_udev);
m_udev = udev_new();
if (!m_udev)
{
raise_exception(std::runtime_error, "udev init failure");
}
}
void
XboxdrvDaemon::init_udev_monitor()
{
// Setup udev monitor and enumerate
m_monitor = udev_monitor_new_from_netlink(m_udev, "udev");
udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "usb", "usb_device");
udev_monitor_enable_receiving(m_monitor);
// FIXME: won't we get devices twice that have been plugged in at
// this point? once from the enumeration, once from the monitor
enumerate_udev_devices();
}
void
XboxdrvDaemon::enumerate_udev_devices()
{
// Enumerate over all devices already connected to the computer
struct udev_enumerate* enumerate = udev_enumerate_new(m_udev);
assert(enumerate);
udev_enumerate_add_match_subsystem(enumerate, "usb");
// not available yet: udev_enumerate_add_match_is_initialized(enumerate);
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry* devices;
struct udev_list_entry* dev_list_entry;
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices)
{
// name is path, value is NULL
const char* path = udev_list_entry_get_name(dev_list_entry);
struct udev_device* device = udev_device_new_from_syspath(m_udev, path);
// manually filter for devtype, as udev enumerate can't do it by itself
const char* devtype = udev_device_get_devtype(device);
if (devtype && strcmp(devtype, "usb_device") == 0)
{
process_match(device);
}
udev_device_unref(device);
}
udev_enumerate_unref(enumerate);
}
void
XboxdrvDaemon::create_pid_file()
{
@ -316,123 +288,6 @@ XboxdrvDaemon::create_pid_file()
}
}
void
XboxdrvDaemon::init_g_usb()
{
assert(!m_usb_gsource);
m_usb_gsource.reset(new USBGSource);
m_usb_gsource->attach(NULL);
}
void
XboxdrvDaemon::init_g_udev()
{
GIOChannel* udev_channel = g_io_channel_unix_new(udev_monitor_get_fd(m_monitor));
g_io_add_watch(udev_channel,
static_cast<GIOCondition>(G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP),
&XboxdrvDaemon::on_udev_data_wrap, this);
g_io_channel_unref(udev_channel);
}
void
XboxdrvDaemon::init_g_dbus()
{
if (m_opts.dbus)
{
try
{
GError* gerror = NULL;
// this calls automatically sets up connection to the main loop
DBusGConnection* connection = dbus_g_bus_get(DBUS_BUS_SESSION, &gerror);
if (!connection)
{
std::ostringstream out;
out << "failed to open connection to bus: " << gerror->message;
g_error_free(gerror);
throw std::runtime_error(out.str());
}
else
{
DBusError error;
dbus_error_init(&error);
int ret = dbus_bus_request_name(dbus_g_connection_get_connection(connection),
"org.seul.Xboxdrv",
DBUS_NAME_FLAG_REPLACE_EXISTING,
&error);
if (dbus_error_is_set(&error))
{
std::ostringstream out;
out << "failed to get unique dbus name: " << error.message;
dbus_error_free(&error);
throw std::runtime_error(out.str());
}
if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
{
raise_exception(std::runtime_error, "failed to become primary owner of dbus name");
}
// FIXME: should unref() these somewhere
XboxdrvGDaemon* daemon = xboxdrv_g_daemon_new(this);
dbus_g_object_type_install_info(XBOXDRV_TYPE_G_DAEMON, &dbus_glib_xboxdrv_daemon_object_info);
dbus_g_connection_register_g_object(connection, "/org/seul/Xboxdrv/Daemon", G_OBJECT(daemon));
for(ControllerSlots::iterator i = m_controller_slots.begin(); i != m_controller_slots.end(); ++i)
{
XboxdrvGController* controller = xboxdrv_g_controller_new(i->get());
dbus_g_object_type_install_info(XBOXDRV_TYPE_G_CONTROLLER, &dbus_glib_xboxdrv_controller_object_info);
dbus_g_connection_register_g_object(connection,
(boost::format("/org/seul/Xboxdrv/ControllerSlots/%d") % (i - m_controller_slots.begin())).str().c_str(),
G_OBJECT(controller));
}
}
}
catch (const std::exception& err)
{
log_error("D-Bus initialisation failed: " << err.what());
}
}
}
void
XboxdrvDaemon::run()
{
try
{
create_pid_file();
init_uinput();
init_udev();
init_udev_monitor();
g_type_init();
// we don't use glib threads, but we still need to init the thread
// system to make glib thread safe
g_thread_init(NULL);
signal(SIGINT, &XboxdrvDaemon::on_sigint);
signal(SIGTERM, &XboxdrvDaemon::on_sigint);
m_gmain = g_main_loop_new(NULL, false);
init_g_usb();
init_g_udev();
init_g_dbus();
log_info("launching into glib main loop");
g_main_loop_run(m_gmain);
log_info("glib main loop finished");
signal(SIGINT, 0);
g_main_loop_unref(m_gmain);
}
catch(const std::exception& err)
{
log_error("fatal exception: " << err.what());
}
}
bool
XboxdrvDaemon::on_wakeup()
{
@ -442,60 +297,6 @@ XboxdrvDaemon::on_wakeup()
return false; // remove the registered idle callback
}
bool
XboxdrvDaemon::on_udev_data(GIOChannel* channel, GIOCondition condition)
{
if (condition == G_IO_OUT)
{
log_error("data can be written");
}
else if (condition == G_IO_PRI)
{
log_error("data can be read");
}
else if (condition == G_IO_ERR)
{
log_error("data error");
}
else if (condition != G_IO_IN)
{
log_error("unknown condition: " << condition);
}
else
{
log_info("trying to read data from udev");
cleanup_threads();
log_info("trying to read data from udev monitor");
struct udev_device* device = udev_monitor_receive_device(m_monitor);
log_info("got data from udev monitor");
if (!device)
{
// seem to be normal, do we get this when the given device is filtered out?
log_debug("udev device couldn't be read: " << device);
}
else
{
const char* action = udev_device_get_action(device);
if (g_logger.get_log_level() >= Logger::kDebug)
{
print_info(device);
}
if (action && strcmp(action, "add") == 0)
{
process_match(device);
}
udev_device_unref(device);
}
}
return true;
}
void
XboxdrvDaemon::check_thread_status()
{
@ -543,85 +344,6 @@ XboxdrvDaemon::check_thread_status()
m_inactive_controllers.end());
}
void
XboxdrvDaemon::print_info(udev_device* device)
{
log_debug("/---------------------------------------------");
log_debug("devpath: " << udev_device_get_devpath(device));
if (udev_device_get_action(device))
log_debug("action: " << udev_device_get_action(device));
//log_debug("init: " << udev_device_get_is_initialized(device));
if (udev_device_get_subsystem(device))
log_debug("subsystem: " << udev_device_get_subsystem(device));
if (udev_device_get_devtype(device))
log_debug("devtype: " << udev_device_get_devtype(device));
if (udev_device_get_syspath(device))
log_debug("syspath: " << udev_device_get_syspath(device));
if (udev_device_get_sysname(device))
log_debug("sysname: " << udev_device_get_sysname(device));
if (udev_device_get_sysnum(device))
log_debug("sysnum: " << udev_device_get_sysnum(device));
if (udev_device_get_devnode(device))
log_debug("devnode: " << udev_device_get_devnode(device));
if (udev_device_get_driver(device))
log_debug("driver: " << udev_device_get_driver(device));
if (udev_device_get_action(device))
log_debug("action: " << udev_device_get_action(device));
//udev_device_get_sysattr_value(device, "busnum");
//udev_device_get_sysattr_value(device, "devnum");
#if 0
// FIXME: only works with newer versions of libudev
{
log_debug("list: ");
struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
while((it = udev_list_entry_get_next(it)) != 0)
{
log_debug(" "
<< udev_list_entry_get_name(it) << " = "
<< udev_list_entry_get_value(it)
);
}
}
{
log_debug("properties: ");
struct udev_list_entry* it = udev_device_get_properties_list_entry(device);
while((it = udev_list_entry_get_next(it)) != 0)
{
log_debug(" "
<< udev_list_entry_get_name(it) << " = "
<< udev_list_entry_get_value(it)
);
}
}
{
log_debug("devlist: ");
struct udev_list_entry* it = udev_device_get_tags_list_entry(device);
while((it = udev_list_entry_get_next(it)) != 0)
{
log_debug(" "
<< udev_list_entry_get_name(it) << " = "
<< udev_list_entry_get_value(it)
);
}
}
#endif
log_debug("\\----------------------------------------------");
}
ControllerSlotPtr
XboxdrvDaemon::find_free_slot(udev_device* dev)
{

View file

@ -37,12 +37,9 @@ class XboxdrvDaemon
private:
static XboxdrvDaemon* s_current;
private:
const Options& m_opts;
struct udev* m_udev;
struct udev_monitor* m_monitor;
boost::scoped_ptr<USBGSource> m_usb_gsource;
GMainLoop* m_gmain;
typedef std::vector<ControllerSlotPtr> ControllerSlots;
ControllerSlots m_controller_slots;
@ -51,7 +48,6 @@ private:
Controllers m_inactive_controllers;
std::auto_ptr<UInput> m_uinput;
GMainLoop* m_gmain;
private:
static void on_sigint(int);
@ -69,16 +65,9 @@ public:
private:
void create_pid_file();
void init_uinput();
void init_udev();
void init_udev_monitor();
void init_g_usb();
void init_g_udev();
void init_g_dbus();
ControllerSlotPtr find_free_slot(udev_device* dev);
void enumerate_udev_devices();
void cleanup_threads();
void process_match(struct udev_device* device);
void print_info(struct udev_device* device);
@ -98,17 +87,10 @@ private:
private:
bool on_wakeup();
bool on_udev_data(GIOChannel* channel, GIOCondition condition);
private:
static gboolean on_wakeup_wrap(gpointer data) {
return static_cast<XboxdrvDaemon*>(data)->on_wakeup();
}
static gboolean on_udev_data_wrap(GIOChannel* channel, GIOCondition condition, gpointer data) {
return static_cast<XboxdrvDaemon*>(data)->on_udev_data(channel, condition);
}
private:
XboxdrvDaemon(const XboxdrvDaemon&);
XboxdrvDaemon& operator=(const XboxdrvDaemon&);

View file

@ -41,12 +41,20 @@
XboxdrvMain::XboxdrvMain(const Options& opts) :
m_opts(opts),
m_gmain(),
m_usb_gsource(),
m_uinput(),
m_jsdev_number(),
m_evdev_number(),
m_use_libusb(false),
m_dev_type()
{
m_gmain = g_main_loop_new(NULL, false);
}
XboxdrvMain::~XboxdrvMain()
{
g_main_loop_unref(m_gmain);
}
ControllerPtr
@ -68,17 +76,6 @@ XboxdrvMain::create_controller()
}
else
{ // regular USB Xbox360 controller
m_use_libusb = true;
int ret = libusb_init(NULL);
if (ret != LIBUSB_SUCCESS)
{
raise_exception(std::runtime_error, "libusb_init() failed: " << usb_strerror(ret));
}
if (m_opts.usb_debug)
{
libusb_set_debug(NULL, 3);
}
// FIXME: this must be libusb_unref_device()'ed, child code must not keep a copy around
libusb_device* dev = 0;
@ -125,6 +122,8 @@ XboxdrvMain::init_controller(const ControllerPtr& controller)
void
XboxdrvMain::run()
{
USBSubsystem usb_subsystem;
ControllerPtr controller = create_controller();
std::auto_ptr<MessageProcessor> message_proc;
init_controller(controller);
@ -141,25 +140,27 @@ XboxdrvMain::run()
if (m_opts.no_uinput)
{
if (!m_opts.quiet)
{
std::cout << "Starting without uinput" << std::endl;
}
message_proc.reset(new DummyMessageProcessor);
}
else
{
if (!m_opts.quiet)
std::cout << "Starting with uinput" << std::endl;
log_debug("creating UInput");
m_uinput.reset(new UInput(m_opts.extra_events));
m_uinput->set_device_names(m_opts.uinput_device_names);
m_uinput->set_device_usbids(m_opts.uinput_device_usbids);
log_debug("creating ControllerSlotConfig");
ControllerSlotConfigPtr config_set = ControllerSlotConfig::create(*m_uinput,
0, m_opts.extra_devices,
m_opts.get_controller_slot());
// After all the ControllerConfig registered their events, finish up
// the device creation
log_debug("finish UInput creation");
m_uinput->finish();
message_proc.reset(new UInputMessageProcessor(*m_uinput, config_set, m_opts));
@ -181,15 +182,7 @@ XboxdrvMain::run()
}
}
GMainLoop* m_gmain = g_main_loop_new(NULL, false);
{
boost::scoped_ptr<USBGSource> usb_gsource;
if (m_use_libusb)
{
usb_gsource.reset(new USBGSource);
usb_gsource->attach(NULL);
}
ControllerThread thread(controller, message_proc, m_opts);
log_debug("launching thread");
@ -202,12 +195,6 @@ XboxdrvMain::run()
log_debug("launching main loop");
g_main_loop_run(m_gmain);
}
g_main_loop_unref(m_gmain);
if (m_use_libusb)
{
libusb_exit(NULL);
}
if (!m_opts.quiet)
{
@ -226,16 +213,14 @@ XboxdrvMain::print_info(libusb_device* dev, const XPadDevice& dev_type, const Op
raise_exception(std::runtime_error, "libusb_get_device_descriptor() failed: " << usb_strerror(ret));
}
std::cout << "USB Device: " << boost::format("%03d:%03d")
% static_cast<int>(libusb_get_bus_number(dev))
% static_cast<int>(libusb_get_device_address(dev)) << std::endl;
std::cout << "Controller: " << dev_type.name << std::endl;
std::cout << "Vendor/Product: " << boost::format("%04x:%04x")
% uint16_t(desc.idVendor) % uint16_t(desc.idProduct) << std::endl;
std::cout << "USB Path: " << boost::format("%03d:%03d")
% static_cast<int>(libusb_get_bus_number(dev))
% static_cast<int>(libusb_get_device_address(dev)) << std::endl;
if (dev_type.type == GAMEPAD_XBOX360_WIRELESS)
std::cout << "Wireless Port: " << opts.wireless_id << std::endl;
else
std::cout << "Wireless Port: -" << std::endl;
std::cout << "Controller Type: " << dev_type.type << std::endl;
//std::cout << "ForceFeedback: " << ((opts.controller.back().uinput.force_feedback) ? "enabled" : "disabled") << std::endl;

View file

@ -21,18 +21,24 @@
#include <memory>
#include <libusb.h>
#include <glib.h>
#include <boost/scoped_ptr.hpp>
#include "xpad_device.hpp"
#include "controller_ptr.hpp"
class UInput;
class Options;
class MessageProcessor;
class Options;
class UInput;
class USBGSource;
class XboxdrvMain
{
private:
const Options& m_opts;
GMainLoop* m_gmain;
boost::scoped_ptr<USBGSource> m_usb_gsource;
std::auto_ptr<UInput> m_uinput;
int m_jsdev_number;
@ -43,6 +49,7 @@ private:
public:
XboxdrvMain(const Options& opts);
~XboxdrvMain();
void run();
private: