Documentation update, fixed guitar support, deadzone support, led indicate jsdev now
This commit is contained in:
parent
c758b6648c
commit
beb61477f9
14 changed files with 359 additions and 148 deletions
2
AUTHORS
2
AUTHORS
|
@ -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
18
NEWS
|
@ -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 #
|
||||
|
|
54
PROTOCOL
54
PROTOCOL
|
@ -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
71
README
|
@ -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
37
TODO
|
@ -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)
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
269
xboxdrv.cpp
269
xboxdrv.cpp
|
@ -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 */
|
||||
|
|
Loading…
Add table
Reference in a new issue