Some headset stuff and usbcat and usbdebug stuff

This commit is contained in:
Ingo Ruhnke 2008-08-07 16:44:23 +02:00
parent 19597b67b3
commit 5296e66fa5
6 changed files with 357 additions and 13 deletions

View file

@ -77,10 +77,10 @@ Interface 0:
Endpoint 1(in): Controller events
Endpoint 2(out): Messages to the controller
Interface 1:
Endpoint 3(in): UNKNOWN (maybe headset)
Endpoint 4(out): UNKNOWN (maybe headset)
Endpoint 5(in): UNKNOWN (maybe headset)
Endpoint 6(out): UNKNOWN (maybe headset)
Endpoint 3(in): Headset mic
Endpoint 4(out): Headset phone
Endpoint 5(in): Headset control port(?)
Endpoint 5(out): UNKNOWN (maybe headset)
Interface 2:
Endpoint 6(in): UNKNOWN (maybe headset)
Interface 3:
@ -91,7 +91,7 @@ On first connect the controller sends:
len: 3 data: 0x01 0x03 0x0e // current LED status
len: 3 data: 0x02 0x03 0x00 // UNKNOWN: maybe headset connection status or volume
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 // UNKNOWN: maybe headset connection status or volume
len: 3 data: 0x08 0x03 0x00 // Headset connection status (0x00 no headset, 0x02 headset)
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
@ -100,6 +100,10 @@ The first four lines are unknown, but seem to be always the same, the
sends them two times on each button press and also two times on first
connect.
send 2 2 0 0
-> Sending to endpoint 2: [3] { 0x02, 0x00, 0x00 }Ep1: [3] { 0x03, 0x03, 0x00 }
Commands send to the controller:
--------------------------------
,--------- type of message
@ -167,6 +171,40 @@ struct Xbox360Msg
unsigned int dummy2 :32; // always 0
unsigned int dummy3 :16; // always 0
} __attribute__((__packed__));
Plugging in a headset (interface 1, endpoint 5):
____ When chatpad is plugged this is 0x01, but only if no headphone is plugged into the headset?!
len: 4 data: 0x00 0x04 0x01 0x00
len: 3 data: 0x01 0x03 0x00
len: 3 data: 0x02 0x03 0x0f
len: 5 data: 0x03 0x05 0xff 0x00 0x00
len: 3 data: 0x04 0x03 0xff
len: 3 data: 0x05 0x03 0x00
Pulling out a headset (interface 1, endpoint 5):
len: 4 data: 0x00 0x04 0x00 0x00
---------
Sending to interface 1, endpoint 5:
This only works with the headset plugged in:
0x00 0x03 0x0N -> { 0x05, 0x03, 0x0N } - sets something to N, with N [0, 1]
0x01 0x03 0x0N -> { 0x01, 0x03, 0x0N } - sets something to N, with N [0, 1]
0x02 0x03 0x0N -> { 0x02, 0x03, 0x0N } - sets something to N, with N [0, f]
0x03 0x05 ???? -> { 0x03, 0x05, 0xff, 0x00, 0x00 } - doesn't seem to set anything, just reply
0x04 ???? ????-> { 0x04, 0x03, 0xff } - doesn't seem to set anything, just reply
0x04 0x04 0x00 0x00 seems to cause status reply
---------
Plugging in a headset (interface 0, endpoint 1): len: 3 data: 0x08 0x03 0x00
Pulling out a headset (interface 0, endpoint 1): len: 3 data: 0x08 0x03 0x02
Headset sends with 8192 bytes per second
The headset might be using isochronous transfer, neither bulk nor interrupt, libusb doesn't support that yet I think
Xbox360 Guitar
==============
@ -220,6 +258,7 @@ struct Xbox360GuitarMsg
unsigned int dummy2 :32; // unused
unsigned int dummy3 :16; // unused
} __attribute__((__packed__));
Xbox360 Wireless
================
@ -285,6 +324,32 @@ len: 2 data: 0x08 0x80
len: 29 data: 0x00 0x0f 0x00 0xf0 0xf0 0xcc 0xfd 0x1f 0x9f 0x70 0xc9 0x00 0x63 0xb0 0x00 0x05 0x13 0xa7 0x20 0x1d 0x30 0x03 0x40 0x01 0x50 0x01 0xff 0xff 0xff
len: 29 data: 0x00 0xf8 0x02 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 0x00
Connecting Chatpad:
-------------------
len: 2 data: 0x08 0xc0 -- headset
len: 29 data: 0x00 0x00 0x00 0x17 0xaa 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
len: 28 data: 0x01 0x00 0x67 0x00 0x0c 0xfd 0x0d 0xf6 0x10 0xd2 0x11 0xe2 0xb0 0x00 0x18 0x01 0x34 0x85 0x00 0xdd 0xdd 0xdd 0xdd 0xd2 0x11 0xe2 0xb0 0x00
len: 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
len: 28 data: 0x01 0xff 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 0x00
len: 29 data: 0x00 0xf9 0x02 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 0x00
len: 29 data: 0x00 0x00 0x00 0x13 0xa2 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 -- battery
len: 2 data: 0x08 0x80
len: 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
Chatpad vs Headphone:
---------------------
____ ???
len: 29 data: 0x00 0x00 0x00 0x17 0xe0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
len: 29 data: 0x00 0x00 0x00 0x17 0xaa 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
_____ ____ ____ ____ ____ ____ ____ ____ ____
len: 28 data: 0x01 0x00 0x67 0x00 0x0c 0xfd 0x0d 0xf6 0x10 0xd2 0x26 0x4d 0x00 0x00 0x18 0x01 0x34 0x85 0x00 0xdd 0xdd 0xdd 0x01 0x50 0x01 0xff 0xff 0xff
len: 28 data: 0x01 0x00 0x67 0x00 0x0c 0xfd 0x0d 0xf6 0x10 0xd2 0x11 0xe2 0xb0 0x00 0x18 0x01 0x34 0x85 0x00 0xdd 0xdd 0xdd 0xdd 0xd2 0x11 0xe2 0xb0 0x00
^- Chatpad
http://www.mp3car.com/vbulletin/input-devices/108554-xbox360-chatpad-awsome-backlit-mini-keyboard-10.html
http://www.youtube.com/watch?v=qWWIuh1vsoM
Pluggin in a headphone without chatpat:
---------------------------------------
@ -334,6 +399,12 @@ Randomly:
____ battery status?!
len: 28 data: 0x01 0xff 0x00 0x41 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
____ ____ Muted?
len: 28 data: 0x01 0xff 0x02 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
len: 28 data: 0x01 0xff 0x02 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 (turn off)
len: 28 data: 0x01 0xff 0x02 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 (turn on)
Connecting the wireless and pressing sync button multiple times:
----------------------------------------------------------------

6
TODO
View file

@ -1,3 +1,9 @@
- locate a USB device with a string or two
- thread away on all endpoints
- read from stdin on the main thread
- send output to file or so
usb -d 005:006 -c 5:in,5:out,6:in,7:in,8:out -o /tmp/out, else stdin
More general button map support:
% ./xboxdrv --buttonmap B=BTN_A,X=BTN_A,Y=KEY_B

View file

@ -4,6 +4,6 @@ env = Environment(CPPFLAGS=["-g", "-O2", "-Wall"])
env.Program("jstest", ["jstest.c"])
env.Program("evtest", ["evtest.c"])
env.Program("usbcat", ["usbcat.cpp"], LIBS = ["usb"])
env.Program("usbdebug", ["usbdebug.cpp"], LIBS = ["usb"])
env.Program("usbdebug", ["usbdebug.cpp"], LIBS = ["usb", "pthread"])
# EOF #

View file

@ -19,6 +19,7 @@
#include <usb.h>
#include <boost/format.hpp>
#include <iostream>
#include <math.h>
#include <string.h>
std::ostream& operator<<(std::ostream& out, struct usb_device* dev)
@ -65,6 +66,106 @@ find_usb_device(uint16_t idVendor, uint16_t idProduct)
return 0;
}
void
write_usb_device(struct usb_device* dev, int interface, int endpoint)
{
struct usb_dev_handle* handle = usb_open(dev);
if (!handle)
{
std::cout << "Error opening usb device" << std::endl;
}
else
{
if (usb_claim_interface(handle, interface) != 0)
{
std::cout << "Error claiming the interface: " << usb_strerror() << std::endl;
if (usb_detach_kernel_driver_np(handle, interface) < 0)
{
std::cout << "Failure to kick kernel driver: " << usb_strerror() << std::endl;
exit(EXIT_FAILURE);
}
if (usb_claim_interface(handle, interface) != 0)
{
std::cout << "Error claiming the interface: " << usb_strerror() << std::endl;
exit(EXIT_FAILURE);
}
}
bool quit = false;
while(!quit)
{
uint8_t data[32];
if (1)
{
int ret = fread(data, sizeof(char), sizeof(data), stdin);
std::cout << ret << std::endl;
usb_interrupt_write(handle, endpoint, (char*)data, ret, 0);
}
else
{
int ret = sizeof(data);
for(int i = 0; i < ret ; ++i)
{
data[i] = int(127 * sin(float(i) / ret * M_PI*2)) + 127;
std::cout << ret << std::endl;
}
std::cout << ret << std::endl;
usb_interrupt_write(handle, endpoint, (char*)data, ret, 0);
}
}
}
}
void
read_usb_device(struct usb_device* dev, int interface, int endpoint)
{
struct usb_dev_handle* handle = usb_open(dev);
if (!handle)
{
std::cout << "Error opening usb device" << std::endl;
}
else
{
if (usb_claim_interface(handle, interface) != 0)
{
std::cout << "Error claiming the interface: " << usb_strerror() << std::endl;
if (usb_detach_kernel_driver_np(handle, interface) < 0)
{
std::cout << "Failure to kick kernel driver: " << usb_strerror() << std::endl;
exit(EXIT_FAILURE);
}
if (usb_claim_interface(handle, interface) != 0)
{
std::cout << "Error claiming the interface: " << usb_strerror() << std::endl;
exit(EXIT_FAILURE);
}
}
bool quit = false;
while(!quit)
{
uint8_t data[8192];
int ret = usb_interrupt_read(handle, endpoint, (char*)data, sizeof(data), 0);
if (ret < 0)
{
std::cerr << "USBError: " << ret << "\n" << usb_strerror() << std::endl;
std::cerr << "Shutting down" << std::endl;
quit = true;
}
fwrite(data, sizeof(char), ret, stdout);
}
}
}
void
cat_usb_device(struct usb_device* dev, int interface, int endpoint)
{
@ -99,7 +200,7 @@ cat_usb_device(struct usb_device* dev, int interface, int endpoint)
while(!quit)
{
uint8_t data[1024];
uint8_t data[32];
int ret = usb_interrupt_read(handle, endpoint, (char*)data, sizeof(data), 0);
if (ret < 0)
{
@ -120,6 +221,58 @@ cat_usb_device(struct usb_device* dev, int interface, int endpoint)
std::cout << std::endl;
}
if (0)
{
for(int i = 0; i < ret; ++i)
data[i] = 255;
int ret2 = usb_interrupt_write(handle, 4, (char*)data, ret, 0);
printf("Ret2: %d\n", ret2);
}
if (0)
{
char arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 255 };
for (int len = 3; len <= 8; ++len)
{
// Sending random data:
for (int front = 0; front < 256; ++front)
{
for (size_t i = 0; i < sizeof(arr); ++i)
{
char ledcmd[] = { front, len, arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i] };
printf("%d %d %d\n", len, front, arr[i]);
usb_interrupt_write(handle, 5, ledcmd, len, 0);
uint8_t data[32];
int ret = usb_interrupt_read(handle, endpoint, (char*)data, sizeof(data), 10);
if (ret == -110)
{
}
else if (ret < 0)
{
std::cout << "USBError: " << ret << "\n" << usb_strerror() << std::endl;
std::cout << "Shutting down" << std::endl;
quit = true;
}
else
{
std::cout << "len: " << ret
<< " data: ";
for(int j = 0; j < ret; ++j)
{
std::cout << boost::format("0x%02x ") % int(data[j]);
}
//std::cout << "\r" << std::flush;
std::cout << std::endl;
}
}
}
}
}
if (0)
{
int len = rand() % 10;
@ -170,7 +323,10 @@ int main(int argc, char** argv)
list_usb_devices();
}
else if ((argc == 4 || argc == 5 || argc == 6) && strcmp("cat", argv[1]) == 0)
else if ((argc == 4 || argc == 5 || argc == 6) &&
(strcmp("cat", argv[1]) == 0 ||
strcmp("read", argv[1]) == 0 ||
strcmp("write", argv[1]) == 0))
{
uint16_t idVendor;
uint16_t idProduct;
@ -198,8 +354,19 @@ int main(int argc, char** argv)
}
else
{
std::cout << "Reading data from: " << dev << " Interface: " << interface << " Endpoint: " << endpoint << std::endl;
cat_usb_device(dev, interface, endpoint);
if (strcmp("cat", argv[1]) == 0)
{
std::cout << "Reading data from: " << dev << " Interface: " << interface << " Endpoint: " << endpoint << std::endl;
cat_usb_device(dev, interface, endpoint);
}
else if (strcmp("read", argv[1]) == 0)
{
read_usb_device(dev, interface, endpoint);
}
else if (strcmp("write", argv[1]) == 0)
{
write_usb_device(dev, interface, endpoint);
}
}
}
else

View file

@ -1,4 +1,5 @@
#include <boost/format.hpp>
#include <signal.h>
#include <usb.h>
#include <sstream>
#include <pthread.h>
@ -11,6 +12,7 @@ class USBDevice;
class EndpointListenerThread;
void print_raw_data(std::ostream& out, uint8_t* data, int len);
bool global_interrupt = false;
struct usb_device*
find_usb_device(uint16_t idVendor, uint16_t idProduct)
@ -90,6 +92,17 @@ public:
{
return usb_interrupt_write(handle, endpoint, (char*)data, len, 0);
}
int ctrl_msg(int requesttype, int request,
int value, int index,
uint8_t* data, int size)
{
return usb_control_msg(handle,
requesttype, request,
value, index,
(char*)data, size,
0 /* timeout */);
}
void print_info()
{
@ -399,12 +412,13 @@ public:
}
bool eol() {
return (idx == sequences.size() || (sequences[idx].eol() && (idx+1) == sequences.size()));
return (idx == sequences.size());
}
void reset() {
for(std::vector<Sequence>::iterator i = sequences.begin(); i != sequences.end(); ++i)
i->reset();
idx = 0;
}
int get() {
@ -507,7 +521,7 @@ void console_probe_cmd(const std::vector<std::string>& args)
}
data.resize(sequences.size());
while(!eol(sequences))
while(!eol(sequences) && !global_interrupt)
{
for(int i = 0; i < int(sequences.size()); ++i)
data[i] = sequences[i].get();
@ -520,7 +534,8 @@ void console_probe_cmd(const std::vector<std::string>& args)
next(sequences);
usleep(500 * 1000);
//usleep(100 * 1000);
usleep(10 * 1000);
}
}
}
@ -547,6 +562,41 @@ void console_send_cmd(const std::vector<std::string>& args)
}
}
void console_ctrl_cmd(const std::vector<std::string>& args)
{
if (args.size() < 5)
{
std::cout << "Usage: ctrl REQUESTTYPE REQUEST VALUE INDEX [DATA]..." << std::endl;
}
else
{ // See USB Specification (usb_20.pdf) page 248
int requesttype = strtol(args[1].c_str(), NULL, 16);
int request = strtol(args[2].c_str(), NULL, 16);
int value = strtol(args[3].c_str(), NULL, 16);
int index = strtol(args[4].c_str(), NULL, 16);
std::vector<uint8_t> data;
for(int i = 5; i < int(args.size()); ++i)
data.push_back(strtol(args[i].c_str(), NULL, 16));
std::cout << "Sending to ctrl: "
<< requesttype << " "
<< request << " "
<< value << " "
<< index << ": ";
if (data.empty())
std::cout << "no data";
else
print_raw_data(std::cout, &*data.begin(), data.size());
int ret = USBDevice::current()->ctrl_msg(requesttype, request,
value, index,
data.empty() ? NULL : &*data.begin(),
data.size());
std::cout << " -> " << ret << " '" << strerror(-ret) << "'" << std::endl;
}
}
std::string strip_comment(const std::string& line)
{
std::string::size_type p = line.find_first_of('#');
@ -612,6 +662,10 @@ void eval_console_cmd(const std::string& line_)
{
console_detach_cmd(args);
}
else if (args[0] == "ctrl")
{
console_ctrl_cmd(args);
}
else if (args[0] == "send")
{
console_send_cmd(args);
@ -639,10 +693,26 @@ void run_console()
std::vector<std::string> cmds = tokenize(line, ";");
for(std::vector<std::string>::iterator i = cmds.begin(); i != cmds.end(); ++i)
eval_console_cmd(*i);
global_interrupt = false;
}
std::cout << std::endl;
}
void signal_callback(int)
{
if (global_interrupt)
{
exit(EXIT_FAILURE);
}
else
{
global_interrupt = true;
std::cout << "INTERRUPT" << std::endl;
}
}
int main(int argc, char** argv)
{
if (argc != 2)
@ -665,6 +735,7 @@ int main(int argc, char** argv)
{
std::cout << boost::format("Opening device with idVendor: 0x%h04x, idProduct: 0x%h04x") % idVendor % idProduct << std::endl;
USBDevice* usbdev = new USBDevice(dev);
signal(SIGINT, signal_callback);
run_console();
delete usbdev;
}

View file

@ -40,6 +40,28 @@ Xbox360Controller::Xbox360Controller(struct usb_device* dev, bool is_guitar)
"Try to run 'rmmod xpad' and start xboxdrv again");
}
}
if (0)
{
char arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 32, 64, 128, 255 };
for (int len = 3; len <= 8; ++len)
{
// Sending random data:
for (int front = 0; front < 256; ++front)
{
for (size_t i = 0; i < sizeof(arr); ++i)
{
char ledcmd[] = { front, len, arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i], arr[i] };
printf("%d %d %d\n", len, front, arr[i]);
usb_interrupt_write(handle, 2, ledcmd, len, 0);
uint8_t data[32];
int ret = usb_interrupt_read(handle, 1 /*EndPoint*/, (char*)data, sizeof(data), 20);
print_raw_data(std::cout, data, ret);
}
}
}
}
}
Xbox360Controller::~Xbox360Controller()
@ -107,6 +129,13 @@ Xbox360Controller::read(XboxGenericMsg& msg, bool verbose)
std::cout << "Xbox360Controller: Rumble Status: " << int(data[2]) << std::endl;
}
}
else if (ret == 3 && data[0] == 0x08 && data[1] == 0x03)
{
if (data[2] == 0x00)
std::cout << "Headset: none";
else if (data[2] == 0x02)
std::cout << "Headset: none";
}
else if (ret == 20 && data[0] == 0x00 && data[1] == 0x14)
{
if (is_guitar)