Skip to content

Commit

Permalink
Created a separate PR for just merging emulation of the Xbox Controll…
Browse files Browse the repository at this point in the history
…er S in addition to the Xbox Controller
  • Loading branch information
faha223 committed Dec 4, 2024
1 parent 7944150 commit 9e05b66
Show file tree
Hide file tree
Showing 16 changed files with 726 additions and 276 deletions.
4 changes: 4 additions & 0 deletions config_spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ general:

input:
bindings:
port1_driver: string
port1: string
port2_driver: string
port2: string
port3_driver: string
port3: string
port4_driver: string
port4: string
peripherals:
port1:
Expand Down
Binary file added data/controller_mask_s.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions data/meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pfiles = [
'controller_mask.png',
'controller_mask_s.png',
'xmu_mask.png',
'logo_sdf.png',
'xemu_64x64.png',
Expand Down
1 change: 1 addition & 0 deletions hw/xbox/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ specific_ss.add(files(
'xbox.c',
'xbox_pci.c',
'xid.c',
'xid-gamepad.c',
))
subdir('nv2a')
subdir('mcpx')
1 change: 1 addition & 0 deletions hw/xbox/nv2a/pgraph/thirdparty/nv2a_vsh_cpu
Submodule nv2a_vsh_cpu added at d5a730
293 changes: 293 additions & 0 deletions hw/xbox/xid-gamepad.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
/*
* QEMU USB XID Devices
*
* Copyright (c) 2013 espes
* Copyright (c) 2017 Jannik Vogel
* Copyright (c) 2018-2021 Matt Borgerson
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include "xid.h"

// #define DEBUG_XID
#ifdef DEBUG_XID
#define DPRINTF printf
#else
#define DPRINTF(...)
#endif

#define USB_VENDOR_MICROSOFT 0x045e

#define GAMEPAD_IN_ENDPOINT_ID 0x02
#define GAMEPAD_OUT_ENDPOINT_ID 0x02

#define USB_XID(obj) \
OBJECT_CHECK(USBXIDGamepadState, (obj), TYPE_USB_XID_GAMEPAD)
#define USB_XID_S(obj) \
OBJECT_CHECK(USBXIDGamepadState, (obj), TYPE_USB_XID_GAMEPAD_S)

static const USBDescIface desc_iface_xbox_gamepad = {
.bInterfaceNumber = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_XID,
.bInterfaceSubClass = 0x42,
.bInterfaceProtocol = 0x00,
.eps =
(USBDescEndpoint[]){
{
.bEndpointAddress = USB_DIR_IN | GAMEPAD_IN_ENDPOINT_ID,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = 0x20,
.bInterval = 4,
},
{
.bEndpointAddress = USB_DIR_OUT | GAMEPAD_OUT_ENDPOINT_ID,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = 0x20,
.bInterval = 4,
},
},
};

static const USBDescDevice desc_device_xbox_gamepad = {
.bcdUSB = 0x0110,
.bMaxPacketSize0 = 0x40,
.bNumConfigurations = 1,
.confs =
(USBDescConfig[]){
{
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.bmAttributes = USB_CFG_ATT_ONE,
.bMaxPower = 50,
.nif = 1,
.ifs = &desc_iface_xbox_gamepad,
},
},
};

static const USBDesc desc_xbox_gamepad = {
.id = {
.idVendor = USB_VENDOR_MICROSOFT,
.idProduct = 0x0202,
.bcdDevice = 0x0100,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
.full = &desc_device_xbox_gamepad,
.str = desc_strings,
};

static const USBDesc desc_xbox_gamepad_s = {
.id = {
.idVendor = USB_VENDOR_MICROSOFT,
.idProduct = 0x0289,
.bcdDevice = 0x0100,
.iManufacturer = STR_MANUFACTURER,
.iProduct = STR_PRODUCT,
.iSerialNumber = STR_SERIALNUMBER,
},
.full = &desc_device_xbox_gamepad,
.str = desc_strings,
};

static const XIDDesc desc_xid_xbox_gamepad = {
.bLength = 0x10,
.bDescriptorType = USB_DT_XID,
.bcdXid = 0x100,
.bType = XID_DEVICETYPE_GAMEPAD,
.bSubType = XID_DEVICESUBTYPE_GAMEPAD,
.bMaxInputReportSize = 20,
.bMaxOutputReportSize = 6,
.wAlternateProductIds = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
};

static const XIDDesc desc_xid_xbox_gamepad_s = {
.bLength = 0x10,
.bDescriptorType = USB_DT_XID,
.bcdXid = 0x100,
.bType = XID_DEVICETYPE_GAMEPAD,
.bSubType = XID_DEVICESUBTYPE_GAMEPAD_S,
.bMaxInputReportSize = 20,
.bMaxOutputReportSize = 6,
.wAlternateProductIds = { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
};

static void usb_xid_gamepad_handle_data(USBDevice *dev, USBPacket *p)
{
USBXIDGamepadState *s = DO_UPCAST(USBXIDGamepadState, dev, dev);

DPRINTF("xid handle_gamepad_data 0x%x %d 0x%zx\n", p->pid, p->ep->nr,
p->iov.size);

switch (p->pid) {
case USB_TOKEN_IN:
if (p->ep->nr == GAMEPAD_IN_ENDPOINT_ID) {
update_input(s);
usb_packet_copy(p, &s->in_state, s->in_state.bLength);
} else {
assert(false);
}
break;
case USB_TOKEN_OUT:
if (p->ep->nr == GAMEPAD_OUT_ENDPOINT_ID) {
usb_packet_copy(p, &s->out_state, s->out_state.length);
update_output(s);
} else {
assert(false);
}
break;
default:
p->status = USB_RET_STALL;
assert(false);
break;
}
}

static void usb_xid_gamepad_class_initfn(ObjectClass *klass, void *data)
{
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

uc->handle_reset = usb_xid_handle_reset;
uc->handle_control = usb_xid_handle_control;
uc->handle_data = usb_xid_gamepad_handle_data;
// uc->handle_destroy = usb_xid_handle_destroy;
uc->handle_attach = usb_desc_attach;
}

static void usb_xbox_gamepad_realize(USBDevice *dev, Error **errp)
{
USBXIDGamepadState *s = USB_XID(dev);
usb_desc_create_serial(dev);
usb_desc_init(dev);
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;

s->xid_desc = &desc_xid_xbox_gamepad;

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;
}

static void usb_xbox_gamepad_s_realize(USBDevice *dev, Error **errp)
{
USBXIDGamepadState *s = USB_XID_S(dev);
usb_desc_create_serial(dev);
usb_desc_init(dev);
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;

s->xid_desc = &desc_xid_xbox_gamepad_s;

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;
}

static Property xid_properties[] = {
DEFINE_PROP_UINT8("index", USBXIDGamepadState, device_index, 0),
DEFINE_PROP_END_OF_LIST(),
};

static const VMStateDescription vmstate_usb_xbox = {
.name = TYPE_USB_XID_GAMEPAD,
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]){ VMSTATE_USB_DEVICE(dev, USBXIDGamepadState),
// FIXME
VMSTATE_END_OF_LIST() },
};

static const VMStateDescription vmstate_usb_xbox_s = {
.name = TYPE_USB_XID_GAMEPAD_S,
.minimum_version_id = 1,
.fields = (VMStateField[]){ VMSTATE_USB_DEVICE(dev, USBXIDGamepadState),
// FIXME
VMSTATE_END_OF_LIST() },
};

static void usb_xbox_gamepad_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

uc->product_desc = "Microsoft Xbox Controller";
uc->usb_desc = &desc_xbox_gamepad;
uc->realize = usb_xbox_gamepad_realize;
uc->unrealize = usb_xbox_gamepad_unrealize;
usb_xid_gamepad_class_initfn(klass, data);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->vmsd = &vmstate_usb_xbox;
device_class_set_props(dc, xid_properties);
dc->desc = "Microsoft Xbox Controller";
}

static void usb_xbox_gamepad_s_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass);

uc->product_desc = "Microsoft Xbox Controller S";
uc->usb_desc = &desc_xbox_gamepad_s;
uc->realize = usb_xbox_gamepad_s_realize;
uc->unrealize = usb_xbox_gamepad_unrealize;
usb_xid_gamepad_class_initfn(klass, data);
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
dc->vmsd = &vmstate_usb_xbox_s;
device_class_set_props(dc, xid_properties);
dc->desc = "Microsoft Xbox Controller S";
}

static const TypeInfo usb_xbox_gamepad_info = {
.name = TYPE_USB_XID_GAMEPAD,
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBXIDGamepadState),
.class_init = usb_xbox_gamepad_class_initfn,
};

static const TypeInfo usb_xbox_gamepad_s_info = {
.name = TYPE_USB_XID_GAMEPAD_S,
.parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBXIDGamepadState),
.class_init = usb_xbox_gamepad_s_class_initfn,
};

static void usb_xid_register_types(void)
{
type_register_static(&usb_xbox_gamepad_info);
type_register_static(&usb_xbox_gamepad_s_info);
}

type_init(usb_xid_register_types)
Loading

0 comments on commit 9e05b66

Please sign in to comment.