Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 71 additions & 24 deletions hw/xbox/xid.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ typedef struct USBXIDState {
QemuInputHandlerState *hs;
bool in_dirty;
XIDGamepadReport in_state;
XIDGamepadReport in_state_capabilities;
XIDGamepadOutputReport out_state;
XIDGamepadOutputReport out_state_capabilities;
} USBXIDState;

static const USBDescIface desc_iface_xbox_gamepad = {
Expand Down Expand Up @@ -158,15 +160,14 @@ static const USBDesc desc_xbox_gamepad = {
static const XIDDesc desc_xid_xbox_gamepad = {
.bLength = 0x10,
.bDescriptorType = USB_DT_XID,
.bcdXid = 1,
.bcdXid = 0x100,
.bType = 1,
.bSubType = 1,
.bMaxInputReportSize = 0x20,
.bMaxOutputReportSize = 0x6,
.wAlternateProductIds = {-1, -1, -1, -1},
.bMaxInputReportSize = 20,
.bMaxOutputReportSize = 6,
.wAlternateProductIds = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
};


#define GAMEPAD_A 0
#define GAMEPAD_B 1
#define GAMEPAD_X 2
Expand Down Expand Up @@ -309,12 +310,19 @@ static void usb_xid_handle_reset(USBDevice *dev)
DPRINTF("xid reset\n");
}

static void update_force_feedback(USBXIDState *s) {
//FIXME: Check actuator endianess
DPRINTF("Set rumble power to 0x%x, 0x%x\n",
s->out_state.left_actuator_strength,
s->out_state.right_actuator_strength);
}

static void usb_xid_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
USBXIDState *s = (USBXIDState *)dev;

DPRINTF("xid handle_control 0x%x 0x%x\n", request, value);
DPRINTF("xid handle_control 0x%x 0x%x (length: %d)\n", request, value, length);

int ret = usb_desc_handle_control(dev, p, request, value,
index, length, data);
Expand All @@ -327,28 +335,35 @@ static void usb_xid_handle_control(USBDevice *dev, USBPacket *p,
/* HID requests */
case ClassInterfaceRequest | HID_GET_REPORT:
DPRINTF("xid GET_REPORT 0x%x\n", value);
if (value == 0x100) { /* input */
assert(s->in_state.bLength <= length);
// s->in_state.bReportId++; /* FIXME: I'm not sure if bReportId is just a counter */
memcpy(data, &s->in_state, s->in_state.bLength);
p->actual_length = s->in_state.bLength;
if (value == 0x0100) { /* input */
if (length <= s->in_state.bLength) {
memcpy(data, &s->in_state, s->in_state.bLength);
p->actual_length = length;
} else {
p->status = USB_RET_STALL;
}
} else {
p->status = USB_RET_STALL;
assert(false);
}
break;
case ClassInterfaceOutRequest | HID_SET_REPORT:
DPRINTF("xid SET_REPORT 0x%x\n", value);
if (value == 0x200) { /* output */
if (value == 0x0200) { /* output */
/* Read length, then the entire packet */
memcpy(&s->out_state, data, sizeof(s->out_state));
assert(s->out_state.length == sizeof(s->out_state));
assert(s->out_state.length <= length);
//FIXME: Check actuator endianess
DPRINTF("Set rumble power to 0x%x, 0x%x\n",
s->out_state.left_actuator_strength,
s->out_state.right_actuator_strength);
p->actual_length = s->out_state.length;
if (length == s->out_state.length) {
memcpy(&s->out_state, data, sizeof(s->out_state));

//FIXME: This should also be a STALL
assert(s->out_state.length == sizeof(s->out_state));

p->actual_length = length;
} else {
p->status = USB_RET_STALL;
}
update_force_feedback(s);
} else {
p->status = USB_RET_STALL;
assert(false);
}
break;
Expand All @@ -360,14 +375,28 @@ static void usb_xid_handle_control(USBDevice *dev, USBPacket *p,
memcpy(data, s->xid_desc, s->xid_desc->bLength);
p->actual_length = s->xid_desc->bLength;
} else {
p->status = USB_RET_STALL;
assert(false);
}
break;
case VendorInterfaceRequest | XID_GET_CAPABILITIES:
DPRINTF("xid XID_GET_CAPABILITIES 0x%x\n", value);
/* FIXME: ! */
p->status = USB_RET_STALL;
//assert(false);
if (value == 0x0100) {
if (length > s->in_state_capabilities.bLength) {
length = s->in_state_capabilities.bLength;
}
memcpy(data, &s->in_state_capabilities, length);
p->actual_length = length;
} else if (value == 0x0200) {
if (length > s->out_state_capabilities.length) {
length = s->out_state_capabilities.length;
}
memcpy(data, &s->out_state_capabilities, length);
p->actual_length = length;
} else {
p->status = USB_RET_STALL;
assert(false);
}
break;
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8)
| USB_REQ_GET_DESCRIPTOR:
Expand Down Expand Up @@ -415,7 +444,12 @@ static void usb_xid_handle_data(USBDevice *dev, USBPacket *p)
}
break;
case USB_TOKEN_OUT:
p->status = USB_RET_STALL;
if (p->ep->nr == 2) {
usb_packet_copy(p, &s->out_state, s->out_state.length);
update_force_feedback(s);
} else {
assert(false);
}
break;
default:
p->status = USB_RET_STALL;
Expand All @@ -442,7 +476,20 @@ static void usb_xbox_gamepad_realize(USBDevice *dev, Error **errp)
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 2);

s->in_state.bLength = sizeof(s->in_state);
s->in_state.bReportId = 0;

s->out_state.length = sizeof(s->out_state);
s->out_state.report_id = 0;

memset(&s->in_state_capabilities, 0xFF, sizeof(s->in_state_capabilities));
s->in_state_capabilities.bLength = sizeof(s->in_state_capabilities);
s->in_state_capabilities.bReportId = 0;

memset(&s->out_state_capabilities, 0xFF, sizeof(s->out_state_capabilities));
s->out_state_capabilities.length = sizeof(s->out_state_capabilities);
s->out_state_capabilities.report_id = 0;


s->hs = qemu_input_handler_register((DeviceState *)(s), &xboxkbd_handler);
s->xid_desc = &desc_xid_xbox_gamepad;
}
Expand Down