Documentation update, fixed guitar support, deadzone support, led indicate jsdev now

This commit is contained in:
Ingo Ruhnke 2008-05-02 18:19:59 +02:00
parent c758b6648c
commit beb61477f9
14 changed files with 359 additions and 148 deletions

View file

@ -10,7 +10,7 @@ XBox Gamepad Userspace Driver Testing:
* Jeff Davidson <supermonkey@gmail.com> (Wireless Controller)
Parts of the code are based on XBox Kernel driver (xpad.c/xpad.h) by:
Parts of the code are based on Xpad Kernel driver (xpad.c/xpad.h) by:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Marko Friedemann <mfr@bmx-chemnitz.de>
* Vojtech Pavlik <vojtech@suse.sz>

18
NEWS
View file

@ -1,12 +1,18 @@
xboxdrv 0.2 -
=========================
xboxdrv 0.2 - (??/May/2008)
===========================
* switched from usb_bulk_read() to usb_interrupt_read(), this fixes
the Guitar Hero controller
* added option to specify the USB path to use, instead of using
automatic detection
* added option to enforce the controller type
* added deadzone configuration support
* added support for Xbox360 wireless gamepads
* added support for the Xbox360 guitar controller
* switched from usb_bulk_read() to usb_interrupt_read(), this fixes
problems with some controller
xboxdrv 0.1 - Apr 13 2008
=========================
xboxdrv 0.1 - (13/Apr/2008)
===========================
* initial release
# EOF #

View file

@ -18,7 +18,9 @@ Xbox:
The A, B, X, Y, black and white buttons on the Xbox pad are 8bit pressure sensitive.
Led: doesn't have LEDs
Rumble: { 0x00, 0x06, 0x00, l, 0x00, b };
+----------- small weight (right side), 0-255
v v-- large weight (left side), 0-255
Rumble: { 0x00, 0x06, 0x00, s, 0x00, large };
^-- length of the message
struct XboxMsg
@ -68,27 +70,40 @@ buttons like the Xbox controller, only LT and RT are analog.
On first connect the controller sends:
len: 3 data: 0x01 0x03 0x0e
len: 3 data: 0x01 0x03 0x0e // current LED status
len: 3 data: 0x02 0x03 0x00
len: 3 data: 0x03 0x03 0x03
len: 3 data: 0x03 0x03 0x03 // Rumble Status (0x00 in the last pos means rumble is disabled, 0x03 is default)
len: 3 data: 0x08 0x03 0x00
len: 20 data: 0x00 0x14 0x00 0x00 0x00 0x00 0x69 0xed 0x23 0xff 0x6b 0x00 0x15 0x03 0x00 0x00 0x00 0x00 0x00 0x00
len: 20 data: 0x00 0x14 0x00 0x00 0x00 0x00 0xfc 0xec 0x23 0xff 0x6b 0x00 0x15 0x03 0x00 0x00 0x00 0x00 0x00 0x00
The first four lines are unknown (guess: calibration data, serial
number, version number?), but seem to be always the same, the "len: 20" ones are event
data of the following form. The controller sends them two times on
each button press and also two times on first connect.
The first four lines are unknown, but seem to be always the same, the
"len: 20" ones are event data of the following form. The controller
sends them two times on each button press and also two times on first
connect.
Commands send to the controller:
--------------------------------
,--------- type of message
v v-- length of message
LED: { 0x01, 0x03, LED_STATUS };
LED Status Update Message, send out after one has changed the led status:
{ 0x01 0x03 LED_STATUS } (blinking states are reported as non-blinking)
+-------- large weight (left side), 0-255
v v-- small weight (right side), 0-255
Rumble: { 0x00, 0x08, 0x00, large, small, 0x00, 0x00, 0x00 };
^ ^-- length of the message
`--------- type of message
Unknown:
sending { 0x02, 0x03, INT } causes a reply of { 0x03, 0x03, INT } (values of 0-3 are supported)
sending { 0x02, 0x03, 0x00 } causes future rumble update messages to be ignored, this seems to be permanent, even disconnecting the controller doesn't reset it
Event Messages:
struct Xbox360Msg
{
// -------------------------
@ -191,14 +206,22 @@ struct Xbox360GuitarMsg
Xbox360 Wireless
================
Endpoint 1: Controller 1
Endpoint 2: Headset 1
Endpoint 3: Controller 1
Endpoint 4: Headset 1
Endpoint 5: Controller 1
Endpoint 6: Headset 1
Endpoint 7: Controller 4
Endpoint 8: Headset 1
The wireless reciever acts as a single USB device, each of the four
controller is on a seperate Interface together with the headset port:
Interface 0:
Endpoint 1: Controller 1
Endpoint 2: Headset 1
Interface 1:
Endpoint 3: Controller 1
Endpoint 4: Headset 1
Interface 2:
Endpoint 5: Controller 1
Endpoint 6: Headset 1
Interface 3:
Endpoint 7: Controller 4
Endpoint 8: Headset 1
v-- typo? might be 0x0c, i.e. length
Rumble: { 0x00, 0x01, 0x0f, 0xc0, 0x00, large, small, 0x00, 0x00, 0x00, 0x00, 0x00 }
^ ^--- ???
@ -309,4 +332,5 @@ len: 29 data: 0x00 0xf8 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0
29 data: 0x00 0x00 0x00 0x40 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
29 data: 0x00 0x00 0x00 0xf0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
# EOF #

71
README
View file

@ -1,9 +1,12 @@
[[ XBox/XBox360 USB Gamepad Driver for Userspace ]]
[[ Xbox/Xbox360 USB Gamepad Driver for Userspace ]]
===================================================
This is a XBox/XBox360 gamepad driver for Linux that works in userspace. It
is a alternative to the xpad kernel driver.
This is a Xbox/Xbox360 gamepad driver for Linux that works in
userspace. It is a alternative to the xpad kernel driver and has
support for Xbox1 gamepads, Xbox360 USB gamepads and Xbox360 wireless
gamepads. The Xbox360 guitar and some Xbox1 dancemats might work too.
[[ Compilation ]]
-----------------
@ -19,13 +22,13 @@ You can compile by typing:
% scons
[[ Running ]]
--------------
First make sure that the xpad kernel module does not get loaded,
either by deleting or renaming it. rmmod might not be enough since it
might be automatically loaded.
might be automatically loaded again.
Next you have to load the uinput kernel module which allows userspace
programms to create input devices and the joydev module which gives
@ -39,23 +42,39 @@ You also have to make sure that you have access rights to
adjust the permissions or run xboxdrv as root.
Once ensured that xpad is out of the way and everything is in palce
plug in your XBox360 gamepad and start the userspace driver with:
plug in your Xbox360 gamepad and start the userspace driver with:
% ./xboxdrv
This will create a /dev/input/js0 and allow you to access the gamepad
This will create /dev/input/js0 and allow you to access the gamepad
from any game. To exit the driver press Ctrl-c.
If you have multiple controllers you need to start multiple instances
If you have multiple wired controllers you need to start multiple instances
of the xboxdrv driver and append the -i argument like this:
% ./xboxdrv -i 1
If you have multiple wireless controller you need to start multiple
instances of the xboxdrv driver and append the --wid argument like
this:
% ./xboxdrv --wid 1
You have to sync the wireless controller as usual.
This will then use the second detected controller, see to see which id
your controller has:
% ./xboxdrv --list-controller
When everything works as expected it is recomment that you run xboxdrv
with the silent option:
% ./xboxdrv --silent
This will suppress the logging of events to the console and will
gurantee that no uneccesarry CPU cycles are wasted.
If you want to abuse the led or rumble of the gamepad for notification
in scripts you can do see via:
@ -63,18 +82,22 @@ in scripts you can do see via:
This will cause a mild rumble and the led to rotate, you can stop it
again via, which also happens to be the command you can use to stop
your XBox360 controller from blinking:
your Xbox360 controller from blinking:
% ./xboxdrv -q
For rumble to work make sure you have connected the controller to a
USB port that has enough power, i.e. an unpowered USB hub might not
work.
[[ SDL Notes ]]
---------------
To let SDL know which axis act as a hat and which act as normal axis
you have to set an environment variable:
% SDL_LINUX_JOYSTICK="'XBox360 Gamepad (userspace driver)' 6 1 0"
% SDL_LINUX_JOYSTICK="'Xbox360 Gamepad (userspace driver)' 6 1 0"
% export SDL_LINUX_JOYSTICK
This will let the DPad act as Hat in case you need that for any
@ -82,12 +105,13 @@ game. For most games the driver should work as-is.
See ftp://ptah.lnf.kth.se/pub/misc/sdl-env-vars for more information.
[[ Troubleshooting ]]
---------------------
1) "Error opening XBox360 controller"
-------------------------------------
1) "No Xbox or Xbox360 controller found"
----------------------------------------
This means that either your controller isn't plugged in or not
recognized by the driver. To fix this you need to know the idVendor
and the idProduct numbers, which you can find out via:
@ -98,13 +122,20 @@ Once done you can try to add them to the array:
XPadDevice xpad_devices[] = { ... } in xboxdrv.c.
If you have success with that, send a patch to grumbel@gmx.de
If you have success with that, send a patch to grumbel@gmx.de, if not,
contact me too, I might be able to provide additional help.
As an alternative you can also use the --device and --type option to
enforce a USB device as well as a controller type an bypass any auto
detection.
2) "Unknown data: bytes: 3 Data: ..."
-------------------------------------
This means that your controller is sending data that isn't understood
by the driver. If your controller still works, you can just ignore it,
the XBox360 controller seems to send out useless data every now and
the Xbox360 controller seems to send out useless data every now and
then. If your controller does not work and you get plenty of those
lines when you move the sticks or press buttons it means that your
controller talks an un-understood protocol and some reverse
@ -115,6 +146,7 @@ of:
Along with all the "Unknown data" lines you get.
3) Program starts and then just does nothing
--------------------------------------------
@ -130,6 +162,7 @@ working correctly you can pass the -v option:
This will cause the driver to output all the events that it received
from the controller.
4) "Error: No stuitable uinput device found"
--------------------------------------------
@ -143,4 +176,12 @@ itself works with:
% ./xboxdrv --no-uinput -v
5) The wireless controller doesn't work
----------------------------------------
You have to sync the controller befor it can be used, restart of the
driver isn't needed and the driver should let you now when it recieves
a connection after you sync the controller.
# EOF #

37
TODO
View file

@ -1,10 +1,14 @@
Pictures of Xbox360 and controller:
http://g-prime.net/x360/
FIX:
=====
be verbose by default, add a quiet option
controller type enforcment is broken
deadzone is broken
add magic to detect which jsX device we are going to get
filter auto known unknown messages
usbcat contains ugly endpoint hack
add magic to detect which jsX device we are going to get (opendir, fmmatch, etc.)
fix guitar support
sigint doesn't work properly
Battery warning: LEDs 1,4 then 2,3 over and over ~10 times rapidly
@ -14,12 +18,6 @@ Easy interface:
--
--buttonmap A:B,B:B,X:X
Controller 1:
Data 2: 0x08 0x80
Controller 2:
Data 2: 0x08 0xc0
* a way to send keyboard combination sequences or more general event sequences
* abs input must be normalized to min/max
@ -101,22 +99,7 @@ Unknown data: bytes: 3 Data: 0x01 0x03 0x00
Unknown data: bytes: 3 Data: 0x08 0x03 0x00
Unknown data: bytes: 3 Data: 0x01 0x03 0x06
*/
// wire: { 0x00, 0x08, 0x00, large, small, 0x00, 0x00, 0x00 };
// wireless: { 0x00, 0x01, 0x0f, 0xc0, 0x00, large, small, 0x00, 0x00, 0x00, 0x00, 0x00 };
^^^^ typo?
void Wireless360Controller::SetRumbleMotors(unsigned char large, unsigned char small)
{
char buf[] = {0x00, 0x01, 0x0f, 0xc0, 0x00, large, small, 0x00, 0x00, 0x00, 0x00, 0x00};
WirelessDevice *device;
device = OSDynamicCast(WirelessDevice, getProvider());
if (device != NULL)
device->SendPacket(buf, sizeof(buf));
}
*/
-----
@ -150,8 +133,6 @@ http://happypenguin.org/show?xboxdrv
http://ubuntuforums.org/showthread.php?t=404577&page=16
http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/OsxDriver
* add jstest, evtest into the source
WirelessHIDDevice::receivedMessage(IOMemoryDescriptor *data)

View file

@ -6,7 +6,7 @@ these tools in your distribution, but especially evtest can sometimes
be hard to come by, so I have included them here for convenience.
usbcat is a little tool to dump content from a usb device, it is just
for debugging and reverse engineering.
for debugging and reverse engineering of the USB protocol of a device.
You can compile them via:

View file

@ -23,8 +23,8 @@
#include "xboxmsg.hpp"
#include "xbox360_controller.hpp"
Xbox360Controller::Xbox360Controller(struct usb_device* dev,
XPadDevice* dev_type)
Xbox360Controller::Xbox360Controller(struct usb_device* dev, bool is_guitar)
: is_guitar(is_guitar)
{
handle = usb_open(dev);
if (!handle)
@ -46,6 +46,12 @@ Xbox360Controller::~Xbox360Controller()
usb_close(handle);
}
void
Xbox360Controller::send_raw(char* buffer, int len)
{
usb_interrupt_write(handle, 2, buffer, len, 0);
}
void
Xbox360Controller::set_rumble(uint8_t left, uint8_t right)
{
@ -56,7 +62,7 @@ Xbox360Controller::set_rumble(uint8_t left, uint8_t right)
void
Xbox360Controller::set_led(uint8_t status)
{
char ledcmd[] = { 1, 3, status };
char ledcmd[] = { 0x01, 0x03, status };
usb_interrupt_write(handle, 2, ledcmd, sizeof(ledcmd), 0);
}
@ -65,7 +71,7 @@ Xbox360Controller::read(XboxGenericMsg& msg)
{
uint8_t data[32];
int ret = usb_interrupt_read(handle, 1 /*EndPoint*/, (char*)data, sizeof(data), 0 /*Timeout*/);
if (ret < 0)
{ // Error
std::ostringstream str;
@ -77,10 +83,30 @@ Xbox360Controller::read(XboxGenericMsg& msg)
// happens with the Xbox360 controller every now and then, just
// ignore, seems harmless, so just ignore
}
else if (ret == 3 && data[0] == 0x01 && data[1] == 0x03)
{
// std::cout << "Xbox360Controller: LED Status: " << int(data[2]) << std::endl;
}
else if (ret == 3 && data[0] == 0x03 && data[1] == 0x03)
{
// data[2] == 0x00 means that rumble is disabled
// data[2] == 0x01 unknown, but rumble works
// data[2] == 0x02 unknown, but rumble works
// data[2] == 0x03 is default with rumble enabled
// std::cout << "Xbox360Controller: Rumble Status: " << int(data[2]) << std::endl;
}
else if (ret == 20 && data[0] == 0x00 && data[1] == 0x14)
{
msg.type = GAMEPAD_XBOX360;
msg.xbox360 = *reinterpret_cast<Xbox360Msg*>(data);
if (is_guitar)
{
msg.type = GAMEPAD_XBOX360_GUITAR;
msg.guitar = *reinterpret_cast<Xbox360GuitarMsg*>(data);
}
else
{
msg.type = GAMEPAD_XBOX360;
msg.xbox360 = *reinterpret_cast<Xbox360Msg*>(data);
}
return true;
}
else

View file

@ -28,17 +28,18 @@ struct XPadDevice;
class Xbox360Controller : public XboxGenericController
{
private:
bool is_guitar;
struct usb_device* dev;
XPadDevice* dev_type;
struct usb_dev_handle* handle;
public:
Xbox360Controller(struct usb_device* dev,
XPadDevice* dev_type);
Xbox360Controller(struct usb_device* dev, bool is_guitar);
~Xbox360Controller();
void set_rumble(uint8_t left, uint8_t right);
void set_led(uint8_t status);
void send_raw(char* buffer, int len);
bool read(XboxGenericMsg& msg);
private:

View file

@ -26,7 +26,6 @@
#include "xbox360_wireless_controller.hpp"
Xbox360WirelessController::Xbox360WirelessController(struct usb_device* dev,
XPadDevice* dev_type,
int controller_id)
{
assert(controller_id >= 0 && controller_id < 4);

View file

@ -28,7 +28,6 @@ class Xbox360WirelessController : public XboxGenericController
{
private:
struct usb_device* dev;
XPadDevice* dev_type;
struct usb_dev_handle* handle;
int endpoint;
int interface;
@ -37,7 +36,6 @@ private:
public:
Xbox360WirelessController(struct usb_device* dev,
XPadDevice* dev_type,
int controller_id);
virtual ~Xbox360WirelessController();

View file

@ -21,8 +21,7 @@
#include "xboxmsg.hpp"
#include "xbox_controller.hpp"
XboxController::XboxController(struct usb_device* dev,
XPadDevice* dev_type)
XboxController::XboxController(struct usb_device* dev)
{
handle = usb_open(dev);
if (!handle)

View file

@ -29,12 +29,10 @@ class XboxController : public XboxGenericController
{
private:
struct usb_device* dev;
XPadDevice* dev_type;
struct usb_dev_handle* handle;
public:
XboxController(struct usb_device* dev,
XPadDevice* dev_type);
XboxController(struct usb_device* dev);
virtual ~XboxController();
void set_rumble(uint8_t left, uint8_t right);

View file

@ -29,6 +29,7 @@ public:
virtual void set_rumble(uint8_t left, uint8_t right) =0;
virtual void set_led(uint8_t status) =0;
virtual void send_raw(char* buffer, int len) {}
virtual bool read(XboxGenericMsg& msg) =0;
private:

View file

@ -30,6 +30,9 @@
#include "xboxdrv.hpp"
// Some ugly global variables, needed for sigint catching
bool global_exit_xboxdrv = false;
XboxGenericController* global_controller = 0;
XPadDevice xpad_devices[] = {
// Evil?! Anymore info we could use to identify the devices?
@ -67,9 +70,9 @@ XPadDevice xpad_devices[] = {
{ GAMEPAD_XBOX, 0x044f, 0x0f07, "Thrustmaster, Inc. Controller" },
{ GAMEPAD_XBOX360, 0x045e, 0x028e, "Microsoft Xbox 360 Controller" },
{ GAMEPAD_XBOX360, 0x0738, 0x4716, "Mad Catz Xbox 360 Controller" },
{ GAMEPAD_XBOX360, 0x162e, 0xbeef, "Joytech Neo-Se Take2" },
{ GAMEPAD_XBOX360_GUITAR, 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer" },
// Do these work?
{ GAMEPAD_XBOX360_WIRELESS, 0x045e, 0x0291, "Microsoft Xbox 360 Wireless Controller" },
{ GAMEPAD_XBOX360_WIRELESS, 0x045e, 0x0719, "Microsoft Xbox 360 Wireless Controller (PC)" },
@ -157,7 +160,7 @@ void list_controller()
std::cout << "\nNo controller detected" << std::endl;
}
bool find_controller_by_path(char* busid, char* devid,struct usb_device** xbox_device)
bool find_controller_by_path(const char* busid, const char* devid,struct usb_device** xbox_device)
{
struct usb_bus* busses = usb_get_busses();
@ -178,8 +181,38 @@ bool find_controller_by_path(char* busid, char* devid,struct usb_device** xbox_d
return 0;
}
/** find the number of the next unused /dev/input/jsX device */
int find_jsdev_number()
{
for(int i = 0; ; ++i)
{
char filename1[32];
char filename2[32];
bool find_xbox360_controller(int id, struct usb_device** xbox_device, XPadDevice** type)
sprintf(filename1, "/dev/input/js%d", i);
sprintf(filename2, "/dev/js%d", i);
if (access(filename1, F_OK) != 0 && access(filename2, F_OK) != 0)
return i;
}
}
/** find the number of the next unused /dev/input/eventX device */
int find_evdev_number()
{
for(int i = 0; ; ++i)
{
char filename[32];
sprintf(filename, "/dev/input/event%d", i);
if (access(filename, F_OK) != 0)
return i;
}
}
bool find_xbox360_controller(int id, struct usb_device** xbox_device, XPadDevice* type)
{
struct usb_bus* busses = usb_get_busses();
@ -202,7 +235,7 @@ bool find_xbox360_controller(int id, struct usb_device** xbox_device, XPadDevice
if (id_count == id)
{
*xbox_device = dev;
*type = &xpad_devices[i];
*type = xpad_devices[i];
return true;
}
else
@ -221,7 +254,7 @@ struct CommandLineOptions
{
bool silent;
bool rumble;
char led;
int led;
int rumble_l;
int rumble_r;
int controller_id;
@ -237,7 +270,7 @@ struct CommandLineOptions
CommandLineOptions() {
silent = false;
rumble = false;
led = 0;
led = -1;
rumble_l = 0;
rumble_r = 0;
controller_id = 0;
@ -268,7 +301,7 @@ void print_command_line_help(int argc, char** argv)
std::cout << " --no-uinput do not try to start uinput event dispatching" << std::endl;
std::cout << std::endl;
std::cout << "Device Options: " << std::endl;
std::cout << " -d, --device BUS:DEV Use device BUS:DEV, do not do any scanning" << std::endl;
std::cout << " -d, --device BUS:DEV Use device BUS:DEV, do not do any scanning" << std::endl;
std::cout << std::endl;
std::cout << "Status Options: " << std::endl;
std::cout << " -l, --led NUM set LED status, see --list-led-values (default: 0)" << std::endl;
@ -281,7 +314,7 @@ void print_command_line_help(int argc, char** argv)
std::cout << " --trigger-as-zaxis Combine LT and RT to form a zaxis instead" << std::endl;
std::cout << " --dpad-as-button DPad sends button instead of axis events" << std::endl;
std::cout << " --type TYPE Ignore autodetection and enforce controller type\n"
<< " (xbox, xbox360, xbox360-wireless, xbox360-guitar)" << std::endl;
<< " (xbox, xbox-mat, xbox360, xbox360-wireless, xbox360-guitar)" << std::endl;
std::cout << std::endl;
std::cout << "Report bugs to Ingo Ruhnke <grumbel@gmx.de>" << std::endl;
}
@ -371,6 +404,10 @@ void parse_command_line(int argc, char** argv, CommandLineOptions& opts)
{
opts.gamepad_type = GAMEPAD_XBOX;
}
else if (strcmp(argv[i], "xbox-mat") == 0)
{
opts.gamepad_type = GAMEPAD_XBOX_MAT;
}
else if (strcmp(argv[i], "xbox360") == 0)
{
opts.gamepad_type = GAMEPAD_XBOX360;
@ -383,19 +420,15 @@ void parse_command_line(int argc, char** argv, CommandLineOptions& opts)
{
opts.gamepad_type = GAMEPAD_XBOX360_WIRELESS;
}
else if (strcmp(argv[i], "xbox-dancemat") == 0)
{
opts.gamepad_type = GAMEPAD_XBOX_MAT;
}
else
{
std::cout << "Error: unknown type: " << argv[i] << std::endl;
std::cout << "Possible types are:" << std::endl;
std::cout << " * xbox" << std::endl;
std::cout << " * xbox-emat" << std::endl;
std::cout << " * xbox360" << std::endl;
std::cout << " * xbox360-guitar" << std::endl;
std::cout << " * xbox360-wireless" << std::endl;
std::cout << " * xbox360-dancemat" << std::endl;
exit(EXIT_FAILURE);
}
}
@ -566,78 +599,107 @@ void parse_command_line(int argc, char** argv, CommandLineOptions& opts)
}
void print_info(struct usb_device* dev,
XPadDevice* dev_type,
const XPadDevice& dev_type,
const CommandLineOptions& opts)
{
std::cout << "USB Device: " << dev->bus->dirname << ":" << dev->filename << std::endl;
std::cout << "Controller: " << boost::format("\"%s\" (idVendor: 0x%04x, idProduct: 0x%04x)")
% (dev_type ? dev_type->name : "unknown") % uint16_t(dev->descriptor.idVendor) % uint16_t(dev->descriptor.idProduct) << std::endl;
if (dev_type->type == GAMEPAD_XBOX360_WIRELESS)
% dev_type.name % uint16_t(dev->descriptor.idVendor) % uint16_t(dev->descriptor.idProduct) << std::endl;
if (dev_type.type == GAMEPAD_XBOX360_WIRELESS)
std::cout << "Wireless Port: " << opts.wireless_id << std::endl;
std::cout << "Controller Type: " << opts.gamepad_type << std::endl;
std::cout << "Deadzone: " << opts.deadzone << std::endl;
std::cout << "Rumble Debug: " << (opts.rumble ? "on" : "off") << std::endl;
std::cout << "Rumble Speed: " << "left: " << opts.rumble_l << " right: " << opts.rumble_r << std::endl;
std::cout << "LED Status: " << int(opts.led) << std::endl;
if (opts.led == -1)
std::cout << "LED Status: " << "auto" << std::endl;
else
std::cout << "LED Status: " << opts.led << std::endl;
}
void controller_loop(XboxGenericController* controller, CommandLineOptions& opts)
void apply_deadzone(XboxGenericMsg& msg, int deadzone)
{
uInput* uinput = 0;
if (!opts.no_uinput)
switch (msg.type)
{
std::cout << "Starting uinput" << std::endl;
uinput = new uInput(opts.gamepad_type, opts.uinput_config);
}
else
{
std::cout << "Starting without uinput" << std::endl;
}
std::cout << "\nYour Xbox360 controller should now be available as /dev/input/jsX and /dev/input/eventX" << std::endl;
std::cout << "Press Ctrl-c to quit" << std::endl;
case GAMEPAD_XBOX:
case GAMEPAD_XBOX_MAT:
if (abs(msg.xbox.x1) < deadzone)
msg.xbox.x1 = 0;
if (abs(msg.xbox.y1) < deadzone)
msg.xbox.y1 = 0;
if (abs(msg.xbox.x2) < deadzone)
msg.xbox.x2 = 0;
if (abs(msg.xbox.y2) < deadzone)
msg.xbox.y2 = 0;
break;
bool quit = false;
while(!quit)
case GAMEPAD_XBOX360:
case GAMEPAD_XBOX360_WIRELESS:
if (abs(msg.xbox360.x1) < deadzone)
msg.xbox360.x1 = 0;
if (abs(msg.xbox360.y1) < deadzone)
msg.xbox360.y1 = 0;
if (abs(msg.xbox360.x2) < deadzone)
msg.xbox360.x2 = 0;
if (abs(msg.xbox360.y2) < deadzone)
msg.xbox360.y2 = 0;
break;
case GAMEPAD_XBOX360_GUITAR:
// FIXME: any use for deadzone here?
break;
default:
assert(!"apply_deadzone(): Unknown gamepad type");
}
}
void controller_loop(uInput* uinput, XboxGenericController* controller, CommandLineOptions& opts)
{
XboxGenericMsg oldmsg;
memset(&oldmsg, 0, sizeof(oldmsg));
while(!global_exit_xboxdrv)
{
XboxGenericMsg msg;
if (controller->read(msg))
{
if (!opts.silent)
std::cout << msg << std::endl;
if (uinput) uinput->send(msg);
apply_deadzone(msg, opts.deadzone);
if (memcmp(&msg, &oldmsg, sizeof(XboxGenericMsg)))
{ // Only send a new event out if something has changed,
// this is useful since some controllers send events
// even if nothing has changed, deadzone can cause this
// too
oldmsg = msg;
if (!opts.silent)
std::cout << msg << std::endl;
if (uinput)
uinput->send(msg);
if (opts.rumble)
{
if (opts.gamepad_type == GAMEPAD_XBOX)
if (opts.rumble)
{
controller->set_rumble(msg.xbox.lt, msg.xbox.rt);
}
else if (opts.gamepad_type == GAMEPAD_XBOX360 ||
opts.gamepad_type == GAMEPAD_XBOX360_WIRELESS)
{
controller->set_rumble(msg.xbox360.lt, msg.xbox360.rt);
if (opts.gamepad_type == GAMEPAD_XBOX)
{
controller->set_rumble(msg.xbox.lt, msg.xbox.rt);
}
else if (opts.gamepad_type == GAMEPAD_XBOX360 ||
opts.gamepad_type == GAMEPAD_XBOX360_WIRELESS)
{
controller->set_rumble(msg.xbox360.lt, msg.xbox360.rt);
}
}
}
}
}
}
int main(int argc, char** argv)
void find_controller(struct usb_device*& dev,
XPadDevice& dev_type,
const CommandLineOptions& opts)
{
srand(time(0));
CommandLineOptions opts;
parse_command_line(argc, argv, opts);
usb_init();
usb_find_busses();
usb_find_devices();
struct usb_device* dev = 0;
XPadDevice* dev_type = 0;
if (opts.busid[0] != '\0' && opts.devid[0] != '\0')
{
if (opts.gamepad_type == GAMEPAD_UNKNOWN)
@ -662,6 +724,42 @@ int main(int argc, char** argv)
exit(EXIT_FAILURE);
}
}
}
int led_count = 0;
void on_sigint(int)
{
if (global_exit_xboxdrv)
{
std::cout << "Ctrl-c pressed twice, exting hard" << std::endl;
exit(EXIT_SUCCESS);
}
else
{
std::cout << "Shutdown initiated" << std::endl;
global_exit_xboxdrv = true;
if (global_controller)
global_controller->set_led(0);
}
}
int main(int argc, char** argv)
{
signal(SIGINT, on_sigint);
CommandLineOptions opts;
parse_command_line(argc, argv, opts);
usb_init();
usb_find_busses();
usb_find_devices();
struct usb_device* dev = 0;
XPadDevice dev_type;
find_controller(dev, dev_type, opts);
if (!dev)
{
@ -670,37 +768,53 @@ int main(int argc, char** argv)
}
else
{
if (opts.gamepad_type == GAMEPAD_UNKNOWN)
if (opts.gamepad_type != GAMEPAD_UNKNOWN)
{ // Override the default gamepad type when given
dev_type.type = opts.gamepad_type;
}
else
{
assert(dev_type);
opts.gamepad_type = dev_type->type;
opts.gamepad_type = dev_type.type;
}
print_info(dev, dev_type, opts);
XboxGenericController* controller = 0;
switch (dev_type->type)
switch (dev_type.type)
{
case GAMEPAD_XBOX:
case GAMEPAD_XBOX_MAT:
controller = new XboxController(dev, dev_type);
controller = new XboxController(dev);
break;
case GAMEPAD_XBOX360_GUITAR:
controller = new Xbox360Controller(dev, true);
break;
case GAMEPAD_XBOX360:
controller = new Xbox360Controller(dev, dev_type);
controller = new Xbox360Controller(dev, false);
break;
case GAMEPAD_XBOX360_WIRELESS:
controller = new Xbox360WirelessController(dev, dev_type, opts.wireless_id);
controller = new Xbox360WirelessController(dev, opts.wireless_id);
break;
default:
assert(!"Unknown gamepad type");
}
controller->set_led(opts.led);
global_controller = controller;
int jsdev_number = find_jsdev_number();
int evdev_number = find_evdev_number();
// FIXME: insert /dev/input/jsX detection magic here
if (opts.led == -1)
controller->set_led(2 + jsdev_number % 4);
else
controller->set_led(opts.led);
controller->set_rumble(opts.rumble_l, opts.rumble_r);
if (opts.instant_exit)
@ -709,10 +823,33 @@ int main(int argc, char** argv)
}
else
{
controller_loop(controller, opts);
uInput* uinput = 0;
if (!opts.no_uinput)
{
std::cout << "Starting with uinput" << std::endl;
uinput = new uInput(opts.gamepad_type, opts.uinput_config);
}
else
{
std::cout << "Starting without uinput" << std::endl;
}
std::cout << "\nYour Xbox/Xbox360 controller should now be available as:" << std::endl
<< " /dev/input/js" << jsdev_number << std::endl
<< " /dev/input/event" << evdev_number << std::endl;
std::cout << "\nPress Ctrl-c to quit\n" << std::endl;
global_exit_xboxdrv = false;
controller_loop(uinput, controller, opts);
delete controller;
delete uinput;
std::cout << "Shutdown complete" << std::endl;
}
}
return 0;
}
/* EOF */