1
0
mirror of https://github.com/gdsports/USBHost_t36 synced 2024-11-24 01:52:23 -05:00

XBox360 Wireless controller

Support for using the Microsoft XBox 360 wireless receiver for windows
to be able to communicate with XBox 360 wireless controllers.

In theory this should support up to 4 controllers.  So far I have only
tested with one as I only have one.

Added a joystick only test that should support up to 4 joystick objects.
This commit is contained in:
Kurt Eckhardt 2018-01-20 16:38:42 -08:00
parent 5e4707a242
commit eaad0684f2
6 changed files with 384 additions and 36 deletions

View File

@ -782,7 +782,7 @@ public:
const uint8_t *manufacturer();
const uint8_t *product();
const uint8_t *serialNumber();
operator bool() { return ((device != nullptr) || (mydevice != nullptr)); } // override as in both USBDriver and in USBHIDInput
operator bool() { return (((device != nullptr) || (mydevice != nullptr)) && connected_); } // override as in both USBDriver and in USBHIDInput
bool available() { return joystickEvent; }
void joystickDataClear();
@ -798,7 +798,7 @@ public:
// setLEDs on PS4(RGB), PS3 simple LED setting (only uses lr)
bool setLEDs(uint8_t lr, uint8_t lg=0, uint8_t lb=0); // sets Leds,
enum { STANDARD_AXIS_COUNT = 10, ADDITIONAL_AXIS_COUNT = 54, TOTAL_AXIS_COUNT = (STANDARD_AXIS_COUNT+ADDITIONAL_AXIS_COUNT) };
typedef enum { UNKNOWN=0, PS3, PS4, XBOXONE} joytype_t;
typedef enum { UNKNOWN=0, PS3, PS4, XBOXONE, XBOX360} joytype_t;
joytype_t joystickType = UNKNOWN;
protected:
// From USBDriver
@ -839,6 +839,7 @@ private:
uint8_t rumble_rValue_ = 0;
uint8_t rumble_timeout_ = 0;
uint8_t leds_[3] = {0,0,0};
uint8_t connected_ = 0; // what type of device if any is connected xbox 360...
// Used by HID code
@ -854,6 +855,7 @@ private:
Transfer_t mytransfers[7] __attribute__ ((aligned(32)));
strbuf_t mystring_bufs[1];
uint8_t rx_ep_ = 0; // remember which end point this object is...
uint16_t rx_size_ = 0;
uint16_t tx_size_ = 0;
Pipe_t *rxpipe_;

View File

@ -44,7 +44,7 @@ static USBDriver *available_drivers = NULL;
// Static buffers used during enumeration. One a single USB device
// may enumerate at once, because USB address zero is used, and
// because this static buffer & state info can't be shared.
static uint8_t enumbuf[256] __attribute__ ((aligned(16)));
static uint8_t enumbuf[512] __attribute__ ((aligned(16)));
static setup_t enumsetup __attribute__ ((aligned(16)));
static uint16_t enumlen;

View File

@ -0,0 +1,195 @@
// Simple test of USB Host Joystick
//
// This example is in the public domain
#include "USBHost_t36.h"
USBHost myusb;
USBHub hub1(myusb);
USBHIDParser hid1(myusb);
USBHIDParser hid2(myusb);
USBHIDParser hid3(myusb);
USBHIDParser hid4(myusb);
#define COUNT_JOYSTICKS 4
JoystickController joysticks[COUNT_JOYSTICKS](myusb);
int user_axis[64];
uint32_t buttons_prev = 0;
USBDriver *drivers[] = {&hub1, &joysticks[0], &joysticks[1], &joysticks[2], &joysticks[3], &hid1, &hid2, &hid3, &hid4};
#define CNT_DEVICES (sizeof(drivers)/sizeof(drivers[0]))
const char * driver_names[CNT_DEVICES] = {"Hub1", "joystick[0D]", "joystick[1D]", "joystick[2D]", "joystick[3D]", "HID1", "HID2", "HID3", "HID4"};
bool driver_active[CNT_DEVICES] = {false, false, false, false};
// Lets also look at HID Input devices
USBHIDInput *hiddrivers[] = {&joysticks[0], &joysticks[1], &joysticks[2], &joysticks[3]};
#define CNT_HIDDEVICES (sizeof(hiddrivers)/sizeof(hiddrivers[0]))
const char * hid_driver_names[CNT_DEVICES] = {"joystick[0H]", "joystick[1H]", "joystick[2H]", "joystick[3H]"};
bool hid_driver_active[CNT_DEVICES] = {false};
bool show_changed_only = false;
uint8_t joystick_left_trigger_value[COUNT_JOYSTICKS] = {0};
uint8_t joystick_right_trigger_value[COUNT_JOYSTICKS] = {0};
uint64_t joystick_full_notify_mask = (uint64_t) - 1;
//=============================================================================
// Setup
//=============================================================================
void setup()
{
while (!Serial) ; // wait for Arduino Serial Monitor
Serial.println("\n\nUSB Host Joystick Testing");
myusb.begin();
}
//=============================================================================
// loop
//=============================================================================
void loop()
{
myusb.Task();
PrintDeviceListChanges();
if (Serial.available()) {
int ch = Serial.read(); // get the first char.
while (Serial.read() != -1) ;
if ((ch == 'b') || (ch == 'B')) {
Serial.println("Only notify on Basic Axis changes");
for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++)
joysticks[joystick_index].axisChangeNotifyMask(0x3ff);
} else if ((ch == 'f') || (ch == 'F')) {
Serial.println("Only notify on Full Axis changes");
for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++)
joysticks[joystick_index].axisChangeNotifyMask(joystick_full_notify_mask);
} else {
if (show_changed_only) {
show_changed_only = false;
Serial.println("\n*** Show All fields mode ***");
} else {
show_changed_only = true;
Serial.println("\n*** Show only changed fields mode ***");
}
}
}
for (int joystick_index = 0; joystick_index < COUNT_JOYSTICKS; joystick_index++) {
if (joysticks[joystick_index].available()) {
uint64_t axis_mask = joysticks[joystick_index].axisMask();
uint64_t axis_changed_mask = joysticks[joystick_index].axisChangedMask();
uint32_t buttons = joysticks[joystick_index].getButtons();
Serial.printf("Joystick(%d): buttons = %x", joystick_index, buttons);
//Serial.printf(" AMasks: %x %x:%x", axis_mask, (uint32_t)(user_axis_mask >> 32), (uint32_t)(user_axis_mask & 0xffffffff));
//Serial.printf(" M: %lx %lx", axis_mask, joysticks[joystick_index].axisChangedMask());
if (show_changed_only) {
for (uint8_t i = 0; axis_changed_mask != 0; i++, axis_changed_mask >>= 1) {
if (axis_changed_mask & 1) {
Serial.printf(" %d:%d", i, joysticks[joystick_index].getAxis(i));
}
}
} else {
for (uint8_t i = 0; axis_mask != 0; i++, axis_mask >>= 1) {
if (axis_mask & 1) {
Serial.printf(" %d:%d", i, joysticks[joystick_index].getAxis(i));
}
}
}
uint8_t ltv;
uint8_t rtv;
switch (joysticks[joystick_index].joystickType) {
default:
break;
case JoystickController::PS4:
ltv = joysticks[joystick_index].getAxis(3);
rtv = joysticks[joystick_index].getAxis(4);
if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) {
joystick_left_trigger_value[joystick_index] = ltv;
joystick_right_trigger_value[joystick_index] = rtv;
joysticks[joystick_index].setRumble(ltv, rtv);
}
break;
case JoystickController::PS3:
ltv = joysticks[joystick_index].getAxis(18);
rtv = joysticks[joystick_index].getAxis(19);
if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) {
joystick_left_trigger_value[joystick_index] = ltv;
joystick_right_trigger_value[joystick_index] = rtv;
joysticks[joystick_index].setRumble(ltv, rtv, 50);
}
break;
case JoystickController::XBOXONE:
case JoystickController::XBOX360:
ltv = joysticks[joystick_index].getAxis(4);
rtv = joysticks[joystick_index].getAxis(5);
if ((ltv != joystick_left_trigger_value[joystick_index]) || (rtv != joystick_right_trigger_value[joystick_index])) {
joystick_left_trigger_value[joystick_index] = ltv;
joystick_right_trigger_value[joystick_index] = rtv;
joysticks[joystick_index].setRumble(ltv, rtv);
Serial.printf(" Set Rumble %d %d", ltv, rtv);
}
break;
}
if (buttons != buttons_prev) {
if (joysticks[joystick_index].joystickType == JoystickController::PS3) {
joysticks[joystick_index].setLEDs((buttons >> 12) & 0xf); // try to get to TRI/CIR/X/SQuare
} else {
uint8_t lr = (buttons & 1) ? 0xff : 0;
uint8_t lg = (buttons & 2) ? 0xff : 0;
uint8_t lb = (buttons & 4) ? 0xff : 0;
joysticks[joystick_index].setLEDs(lr, lg, lb);
}
buttons_prev = buttons;
}
Serial.println();
joysticks[joystick_index].joystickDataClear();
}
}
}
//=============================================================================
// Show when devices are added or removed
//=============================================================================
void PrintDeviceListChanges() {
for (uint8_t i = 0; i < CNT_DEVICES; i++) {
if (*drivers[i] != driver_active[i]) {
if (driver_active[i]) {
Serial.printf("*** Device %s - disconnected ***\n", driver_names[i]);
driver_active[i] = false;
} else {
Serial.printf("*** Device %s %x:%x - connected ***\n", driver_names[i], drivers[i]->idVendor(), drivers[i]->idProduct());
driver_active[i] = true;
const uint8_t *psz = drivers[i]->manufacturer();
if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz);
psz = drivers[i]->product();
if (psz && *psz) Serial.printf(" product: %s\n", psz);
psz = drivers[i]->serialNumber();
if (psz && *psz) Serial.printf(" Serial: %s\n", psz);
}
}
}
for (uint8_t i = 0; i < CNT_HIDDEVICES; i++) {
if (*hiddrivers[i] != hid_driver_active[i]) {
if (hid_driver_active[i]) {
Serial.printf("*** HID Device %s - disconnected ***\n", hid_driver_names[i]);
hid_driver_active[i] = false;
} else {
Serial.printf("*** HID Device %s %x:%x - connected ***\n", hid_driver_names[i], hiddrivers[i]->idVendor(), hiddrivers[i]->idProduct());
hid_driver_active[i] = true;
const uint8_t *psz = hiddrivers[i]->manufacturer();
if (psz && *psz) Serial.printf(" manufacturer: %s\n", psz);
psz = hiddrivers[i]->product();
if (psz && *psz) Serial.printf(" product: %s\n", psz);
psz = hiddrivers[i]->serialNumber();
if (psz && *psz) Serial.printf(" Serial: %s\n", psz);
}
}
}
}

View File

@ -182,6 +182,7 @@ void loop()
break;
case JoystickController::XBOXONE:
case JoystickController::XBOX360:
ltv = joystick1.getAxis(4);
rtv = joystick1.getAxis(5);
if ((ltv != joystick_left_trigger_value) || (rtv != joystick_right_trigger_value)) {

View File

@ -32,6 +32,7 @@
// doing other features.
JoystickController::product_vendor_mapping_t JoystickController::pid_vid_mapping[] = {
{ 0x045e, 0x02ea, XBOXONE, false },{ 0x045e, 0x02dd, XBOXONE, false },
{ 0x045e, 0x0719, XBOX360, false},
{ 0x054C, 0x0268, PS3, true},
{ 0x054C, 0x05C4, PS4, true}, {0x054C, 0x09CC, PS4, true }
};
@ -135,6 +136,23 @@ bool JoystickController::setRumble(uint8_t lValue, uint8_t rValue, uint8_t timeo
println("XBoxOne rumble transfer fail");
}
return true; //
case XBOX360:
txbuf_[0] = 0x00;
txbuf_[1] = 0x01;
txbuf_[2] = 0x0F;
txbuf_[3] = 0xC0;
txbuf_[4] = 0x00;
txbuf_[5] = lValue;
txbuf_[6] = rValue;
txbuf_[7] = 0x00;
txbuf_[8] = 0x00;
txbuf_[9] = 0x00;
txbuf_[10] = 0x00;
txbuf_[11] = 0x00;
if (!queue_Data_Transfer(txpipe_, txbuf_, 12, this)) {
println("XBox360 rumble transfer fail");
}
return true;
}
return false;
}
@ -153,6 +171,27 @@ bool JoystickController::setLEDs(uint8_t lr, uint8_t lg, uint8_t lb)
return transmitPS3UserFeedbackMsg();
case PS4:
return transmitPS4UserFeedbackMsg();
case XBOX360:
// 0: off, 1: all blink then return to before
// 2-5(TL, TR, BL, BR) - blink on then stay on
// 6-9() - On
// ...
txbuf_[1] = 0x00;
txbuf_[2] = 0x08;
txbuf_[3] = 0x40 + lr;
txbuf_[4] = 0x00;
txbuf_[5] = 0x00;
txbuf_[6] = 0x00;
txbuf_[7] = 0x00;
txbuf_[8] = 0x00;
txbuf_[9] = 0x00;
txbuf_[10] = 0x00;
txbuf_[11] = 0x00;
if (!queue_Data_Transfer(txpipe_, txbuf_, 12, this)) {
println("XBox360 set leds fail");
}
return true;
case XBOXONE:
default:
return false;
}
@ -213,11 +252,16 @@ hidclaim_t JoystickController::claim_collection(USBHIDParser *driver, Device_t *
if (topusage != 0x10004 && topusage != 0x10005) return CLAIM_NO;
// only claim from one physical device
if (mydevice != NULL && dev != mydevice) return CLAIM_NO;
// Also don't allow us to claim if it is used as a standard usb object (XBox...)
if (device != nullptr) return CLAIM_NO;
mydevice = dev;
collections_claimed++;
anychange = true; // always report values on first read
driver_ = driver; // remember the driver.
driver_->setTXBuffers(txbuf_, nullptr, sizeof(txbuf_));
connected_ = true; // remember that hardware is actually connected...
// Lets see if we know what type of joystick this is. That is, is it a PS3 or PS4 or ...
joystickType = mapVIDPIDtoJoystickType(mydevice->idVendor, mydevice->idProduct, false);
@ -323,7 +367,7 @@ void JoystickController::hid_input_end()
bool JoystickController::hid_process_out_data(const Transfer_t *transfer)
{
Serial.printf("JoystickController::hid_process_out_data\n");
//Serial.printf("JoystickController::hid_process_out_data\n");
return true;
}
@ -339,14 +383,19 @@ void JoystickController::joystickDataClear() {
// Example: XBox One controller.
//*****************************************************************************
static uint8_t start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00};
static uint8_t xboxone_start_input[] = {0x05, 0x20, 0x00, 0x01, 0x00};
static uint8_t xbox360w_inquire_present[] = {0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
println("JoystickController claim this=", (uint32_t)this, HEX);
// only claim at device level
if (type != 0) return false;
// Don't try to claim if it is used as USB device or HID device
if (mydevice != NULL) return false;
if (device != nullptr) return false;
// Try claiming at the interface level.
if (type != 1) return false;
print_hexbytes(descriptors, len);
JoystickController::joytype_t jtype = mapVIDPIDtoJoystickType(dev->idVendor, dev->idProduct, true);
@ -354,21 +403,38 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
if (jtype == UNKNOWN)
return false;
// XBOX One
// 0 1 2 3 4 5 6 7 8 *9 10 1 2 3 4 5 *6 7 8 9 20 1 2 3 4 5 6 7 8 9 30 1...
// 09 04 00 00 02 FF 47 D0 00 07 05 02 03 40 00 04 07 05 82 03 40 00 04 09 04 01 00 00 FF 47 D0 00
// Lets do some verifications to make sure.
// XBOX 360 wireless... Has 8 interfaces. 4 joysticks (1, 3, 5, 7) and 4 headphones assume 2,4,6, 8...
// Shows data for #1 only...
// Also they have some unknown data type we need to ignore between interface and end points.
// 0 1 2 3 4 5 6 7 8 *9 10 1 2 3 4 5 *6 7 8 9 20 1 2 3 4 5 6 7 8
// 09 04 00 00 02 FF 5D 81 00 14 22 00 01 13 81 1D 00 17 01 02 08 13 01 0C 00 0C 01 02 08
// 29 30 1 2 3 4 5 6 7 8 9 40 41 42
// 07 05 81 03 20 00 01 07 05 01 03 20 00 08
if (len < 9+7+7) return false;
// Some common stuff for both XBoxs
uint32_t count_end_points = descriptors[4];
if (count_end_points < 2) return false;
if (descriptors[5] != 0xff) return false; // bInterfaceClass, 3 = HID
uint32_t rxep = 0;
rx_ep_ = 0;
uint32_t txep = 0;
uint8_t rx_interval = 0;
uint8_t tx_interval = 0;
rx_size_ = 0;
tx_size_ = 0;
uint32_t descriptor_index = 9;
while (count_end_points-- && ((rxep == 0) || txep == 0)) {
if (descriptors[descriptor_index+1] == 0x22) {
if (descriptors[descriptor_index] != 0x14) return false; // only support specific versions...
descriptor_index += descriptors[descriptor_index]; // XBox360w ignore this unknown setup...
}
while (count_end_points-- && ((rx_ep_ == 0) || txep == 0)) {
if (descriptors[descriptor_index] != 7) return false; // length 7
if (descriptors[descriptor_index+1] != 5) return false; // ep desc
if ((descriptors[descriptor_index+3] == 3) // Type 3...
@ -376,24 +442,26 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
&& (descriptors[descriptor_index+5] == 0)) {
// have a bulk EP size
if (descriptors[descriptor_index+2] & 0x80 ) {
rxep = descriptors[descriptor_index+2];
rx_ep_ = descriptors[descriptor_index+2];
rx_size_ = descriptors[descriptor_index+4];
rx_interval = descriptors[descriptor_index+6];
} else {
txep = descriptors[descriptor_index+2];
tx_size_ = descriptors[descriptor_index+4];
tx_interval = descriptors[descriptor_index+6];
}
}
descriptor_index += 7; // setup to look at next one...
}
if ((rxep == 0) || (txep == 0)) return false; // did not find two end points.
print("JoystickController, rxep=", rxep & 15);
if ((rx_ep_ == 0) || (txep == 0)) return false; // did not find two end points.
print("JoystickController, rx_ep_=", rx_ep_ & 15);
print("(", rx_size_);
print("), txep=", txep);
print("(", tx_size_);
println(")");
rxpipe_ = new_Pipe(dev, 2, rxep & 15, 1, rx_size_);
rxpipe_ = new_Pipe(dev, 3, rx_ep_ & 15, 1, rx_size_, rx_interval);
if (!rxpipe_) return false;
txpipe_ = new_Pipe(dev, 2, txep, 0, tx_size_);
txpipe_ = new_Pipe(dev, 3, txep, 0, tx_size_, tx_interval);
if (!txpipe_) {
//free_Pipe(rxpipe_);
return false;
@ -403,7 +471,13 @@ bool JoystickController::claim(Device_t *dev, int type, const uint8_t *descripto
txpipe_->callback_function = tx_callback;
queue_Data_Transfer(txpipe_, start_input, sizeof(start_input), this);
if (jtype == XBOXONE) {
queue_Data_Transfer(txpipe_, xboxone_start_input, sizeof(xboxone_start_input), this);
connected_ = true; // remember that hardware is actually connected...
} else if (jtype == XBOX360) {
queue_Data_Transfer(txpipe_, xbox360w_inquire_present, sizeof(xbox360w_inquire_present), this);
connected_ = 0; // remember that hardware is actually connected...
}
memset(axis, 0, sizeof(axis)); // clear out any data.
joystickType = jtype; // remember we are an XBox One.
return true;
@ -447,18 +521,39 @@ typedef struct {
// dpad up, down left, right
// lb, rb, left stick, right stick
// Axis:
// lt, rt, lx, xy, rx, ry
// lt, rt, lx, ly, rx, ry
//
uint16_t buttons;
int16_t axis[6];
} xbox1data20_t;
typedef struct {
uint8_t state;
uint8_t id_or_type;
uint16_t controller_status;
uint16_t unknown;
// From online references button order:
// sync, dummy, start, back, a, b, x, y
// dpad up, down left, right
// lb, rb, left stick, right stick
// Axis:
// lt, rt, lx, ly, rx, ry
//
uint16_t buttons;
uint8_t lt;
uint8_t rt;
int16_t axis[4];
} xbox360data_t;
static const uint8_t xbox_axis_order_mapping[] = {4, 5, 0, 1, 2, 3};
void JoystickController::rx_data(const Transfer_t *transfer)
{
// print("JoystickController::rx_data: ");
// print_hexbytes((uint8_t*)transfer->buffer, transfer->length);
print("JoystickController::rx_data: ");
print_hexbytes((uint8_t*)transfer->buffer, transfer->length);
if (joystickType == XBOXONE) {
// Process XBOX One data
axis_mask_ = 0x3f;
axis_changed_mask_ = 0; // assume none for now
xbox1data20_t *xb1d = (xbox1data20_t *)transfer->buffer;
@ -473,12 +568,66 @@ void JoystickController::rx_data(const Transfer_t *transfer)
int axis_value = (i < 2)? (int)(uint16_t)xb1d->axis[i] : xb1d->axis[i];
if (axis_value != axis[xbox_axis_order_mapping[i]]) {
axis[xbox_axis_order_mapping[i]] = axis_value;
axis_changed_mask_ |= (1 << xbox_axis_order_mapping[i]);
anychange = true;
}
}
joystickEvent = true;
}
} else if (joystickType == XBOX360) {
// First byte appears to status - if the byte is 0x8 it is a connect or disconnect of the controller.
xbox360data_t *xb360d = (xbox360data_t *)transfer->buffer;
if (xb360d->state == 0x08) {
if (xb360d->id_or_type != connected_) {
connected_ = xb360d->id_or_type; // remember it...
if (connected_) {
println("XBox360w - Connected type:", connected_, HEX);
// rx_ep_ should be 1, 3, 5, 7 for the wireless convert to 2-5 on led
setLEDs(2+rx_ep_/2); // Right now hard coded to first joystick...
} else {
println("XBox360w - disconnected");
}
}
} else if((xb360d->id_or_type == 0x00) && (xb360d->controller_status & 0x1300)) {
// Controller status report - Maybe we should save away and allow the user access?
println("XBox360w - controllerStatus: ", xb360d->controller_status, HEX);
} else if(xb360d->id_or_type == 0x01) { // Lets only process report 1.
//const uint8_t *pbuffer = (uint8_t*)transfer->buffer;
//for (uint8_t i = 0; i < transfer->length; i++) Serial.printf("%02x ", pbuffer[i]);
//Serial.printf("\n");
if (buttons != xb360d->buttons) {
buttons = xb360d->buttons;
anychange = true;
}
axis_mask_ = 0x3f;
axis_changed_mask_ = 0; // assume none for now
for (uint8_t i = 0; i < 4; i++) {
if (axis[i] != xb360d->axis[i]) {
axis[i] = xb360d->axis[i];
axis_changed_mask_ |= (1 << i);
anychange = true;
}
}
// the two triggers show up as 4 and 5
if (axis[4] != xb360d->lt) {
axis[4] = xb360d->lt;
axis_changed_mask_ |= (1 << 4);
anychange = true;
}
if (axis[5] != xb360d->rt) {
axis[5] = xb360d->rt;
axis_changed_mask_ |= (1 << 5);
anychange = true;
}
if (anychange) joystickEvent = true;
}
}
queue_Data_Transfer(rxpipe_, rxbuf_, rx_size_, this);
}

View File

@ -9,7 +9,7 @@ USBSerial KEYWORD1
AntPlus KEYWORD1
JoystickController KEYWORD1
RawHIDController KEYWORD1
BluetoothController KEYWORD1
# Common Functions
Task KEYWORD2
idVendor KEYWORD2
@ -90,6 +90,7 @@ joystickType KEYWORD2
PS3 LITERAL1
PS4 LITERAL1
XBOXONE LITERAL1
XBOX360 LITERAL1
# USBSerial
USBHOST_SERIAL_7E1 LITERAL1