From 0691b8bfb40fa9a37d54d87fb31b1f0d17a2159c Mon Sep 17 00:00:00 2001 From: ergo720 Date: Mon, 2 Jul 2018 01:35:24 +0200 Subject: [PATCH] More hub init + some refactoring --- build/win32/Cxbx.vcxproj | 4 +- build/win32/Cxbx.vcxproj.filters | 10 +- src/Common/{Cxbx.cpp => CxbxCommon.cpp} | 0 src/{Cxbx.h => CxbxCommon.h} | 0 src/CxbxKrnl/CxbxKrnl.h | 2 +- src/devices/usb/Hub.cpp | 187 +++++++++++++++++++----- src/devices/usb/Hub.h | 12 +- src/devices/usb/OHCI.cpp | 21 +-- src/devices/usb/OHCI.h | 1 - src/devices/usb/USBDevice.cpp | 2 + src/devices/usb/USBDevice.h | 4 +- src/devices/usb/UsbCommon.h | 117 ++++++++------- 12 files changed, 250 insertions(+), 110 deletions(-) rename src/Common/{Cxbx.cpp => CxbxCommon.cpp} (100%) rename src/{Cxbx.h => CxbxCommon.h} (100%) diff --git a/build/win32/Cxbx.vcxproj b/build/win32/Cxbx.vcxproj index 40b494cc5..3df1e1a94 100644 --- a/build/win32/Cxbx.vcxproj +++ b/build/win32/Cxbx.vcxproj @@ -295,7 +295,7 @@ - + @@ -420,7 +420,7 @@ - + diff --git a/build/win32/Cxbx.vcxproj.filters b/build/win32/Cxbx.vcxproj.filters index 3fe313af4..dd8666214 100644 --- a/build/win32/Cxbx.vcxproj.filters +++ b/build/win32/Cxbx.vcxproj.filters @@ -284,7 +284,6 @@ Emulator - GUI @@ -295,6 +294,9 @@ Hardware\Usb + + + GUI GUI @@ -343,9 +345,6 @@ Kernel - - Shared - Shared @@ -594,6 +593,9 @@ Hardware\Usb + + + Shared GUI diff --git a/src/Common/Cxbx.cpp b/src/Common/CxbxCommon.cpp similarity index 100% rename from src/Common/Cxbx.cpp rename to src/Common/CxbxCommon.cpp diff --git a/src/Cxbx.h b/src/CxbxCommon.h similarity index 100% rename from src/Cxbx.h rename to src/CxbxCommon.h diff --git a/src/CxbxKrnl/CxbxKrnl.h b/src/CxbxKrnl/CxbxKrnl.h index 9bf123098..e3542e86d 100644 --- a/src/CxbxKrnl/CxbxKrnl.h +++ b/src/CxbxKrnl/CxbxKrnl.h @@ -34,7 +34,7 @@ #ifndef CXBXKRNL_H #define CXBXKRNL_H -#include "Cxbx.h" +#include "CxbxCommon.h" #include "Common/Xbe.h" #undef FIELD_OFFSET // prevent macro redefinition warnings diff --git a/src/devices/usb/Hub.cpp b/src/devices/usb/Hub.cpp index 40d4bb4d5..f562b3991 100644 --- a/src/devices/usb/Hub.cpp +++ b/src/devices/usb/Hub.cpp @@ -36,6 +36,7 @@ #include "OHCI.h" #include "Hub.h" +#include "..\CxbxKrnl\EmuKrnl.h" // For EmuWarning #define NUM_PORTS 8 @@ -55,15 +56,15 @@ int PlayerToUsbArray[] = { }; struct USBHubPort { - USBPort port; // downstream ports of the hub + USBPort port; // downstream port status uint16_t wPortStatus; uint16_t wPortChange; }; struct USBHubState { - XboxDeviceState dev; + XboxDeviceState dev; // hub device status USBEndpoint* intr; - USBHubPort ports[NUM_PORTS]; + USBHubPort ports[NUM_PORTS]; // downstream ports of the hub }; USBDescIface::USBDescIface(bool bDefault) @@ -83,8 +84,12 @@ USBDescIface::USBDescIface(bool bDefault) } USBDescIface::~USBDescIface() -{ - delete descs; +{ + delete descs; // always one struct of this? + if (bNumEndpoints != 1) { + delete[] eps; + return; + } delete eps; } @@ -108,7 +113,14 @@ USBDescDevice::USBDescDevice(bool bDefault) } } -USBDescDevice::~USBDescDevice() { delete confs; } +USBDescDevice::~USBDescDevice() +{ + if (bNumConfigurations != 1) { + delete[] confs; + return; + } + delete confs; +} static const USBDescDevice desc_device_hub(true); @@ -255,12 +267,12 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev) int i; if (dev->Port->HubCount == 5) { - DbgPrintf("Hub: chain too deep"); + DbgPrintf("Hub: chain too deep\n"); return -1; } - usb_desc_create_serial(dev); - usb_desc_init(dev); + CreateSerial(dev); + UsbDescInit(dev); s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); for (i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; @@ -274,6 +286,7 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev) } /* +* From XQEMU: * This function creates a serial number for a usb device. * The serial number should: * (a) Be unique within the emulator. @@ -287,52 +300,150 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev) */ void Hub::CreateSerial(XboxDeviceState* dev) { - DeviceState *hcd = dev->qdev.parent_bus->parent; const USBDesc* desc = GetUsbDeviceDesc(dev); int index = desc->id.iSerialNumber; + USBDescString* s; char serial[64]; char* path; int dst; - if (dev->serial) { - /* 'serial' usb bus property has priority if present */ - usb_desc_set_string(dev, index, dev->serial); - return; - } - assert(index != 0 && desc->str[index] != NULL); - dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]); - path = qdev_get_dev_path(hcd); - if (path) { - dst += snprintf(serial + dst, sizeof(serial) - dst, "-%s", path); - } - dst += snprintf(serial + dst, sizeof(serial) - dst, "-%s", dev->port->path); - usb_desc_set_string(dev, index, serial); + dst = std::snprintf(serial, sizeof(serial), "%s", desc->str[index]); + dst += std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", m_UsbDev->m_PciPath); + dst += std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", dev->Port->Path); + + QLIST_FOREACH(s, &dev->Strings, next) { + if (s->index == index) { + break; + } + } + + if (s == nullptr) { + s = new USBDescString; + s->index = index; + QLIST_INSERT_HEAD(&dev->Strings, s, next); + } + + s->str = serial; } const USBDesc* Hub::GetUsbDeviceDesc(XboxDeviceState* dev) { USBDeviceClass* klass = dev->klass; - if (dev->usb_desc) { - return dev->usb_desc; + if (dev->UsbDesc) { + return dev->UsbDesc; } return klass->usb_desc; } - -void usb_desc_set_string(USBDevice *dev, uint8_t index, const char *str) -{ - USBDescString *s; - QLIST_FOREACH(s, &dev->strings, next) { - if (s->index == index) { +void Hub::UsbDescInit(XboxDeviceState* dev) +{ + const USBDesc* desc = GetUsbDeviceDesc(dev); + + assert(desc != NULL); + dev->Speed = USB_SPEED_FULL; + dev->SpeedMask = 0; + if (desc->full) { + dev->SpeedMask |= USB_SPEED_MASK_FULL; + } + UsbDescSetDefaults(dev); +} + +void Hub::UsbDescSetDefaults(XboxDeviceState* dev) +{ + const USBDesc *desc = GetUsbDeviceDesc(dev); + + assert(desc != NULL); + switch (dev->Speed) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: { + dev->Device = desc->full; break; } + default: + EmuWarning("Unknown speed parameter %d set in %s", dev->ProductDesc.c_str()); } - if (s == NULL) { - s = g_malloc0(sizeof(*s)); - s->index = index; - QLIST_INSERT_HEAD(&dev->strings, s, next); - } - g_free(s->str); - s->str = g_strdup(str); + UsbDescSetConfig(dev, 0); } + +int Hub::UsbDescSetConfig(XboxDeviceState* dev, int value) +{ + int i; + + if (value == 0) { // default configuration + dev->Configuration = 0; + dev->NumInterfaces = 0; + dev->Config = nullptr; + } + else { + for (i = 0; i < dev->Device->bNumConfigurations; i++) { // select the configuration specified + if (dev->Device->confs[i].bConfigurationValue == value) { + dev->Configuration = value; + dev->NumInterfaces = dev->Device->confs[i].bNumInterfaces; + dev->Config = dev->Device->confs + i; + assert(dev->NumInterfaces <= USB_MAX_INTERFACES); + } + } + if (i < dev->Device->bNumConfigurations) { + return -1; + } + } + + for (i = 0; i < dev->NumInterfaces; i++) { // setup all interfaces for the selected configuration + UsbDescSetInterface(dev, i, 0); + } + for (; i < USB_MAX_INTERFACES; i++) { // null the remaining interfaces + dev->AltSetting[i] = 0; + dev->Ifaces[i] = nullptr; + } + + return 0; +} + +int Hub::UsbDescSetInterface(XboxDeviceState* dev, int index, int value) +{ + const USBDescIface* iface; + int old; + + iface = UsbDescFindInterface(dev, index, value); + if (iface == NULL) { + return -1; + } + + old = dev->altsetting[index]; + dev->altsetting[index] = value; + dev->ifaces[index] = iface; + usb_desc_ep_init(dev); + + if (old != value) { + usb_device_set_interface(dev, index, old, value); + } + return 0; +} + +const USBDescIface* Hub::UsbDescFindInterface(XboxDeviceState* dev, int nif, int alt) +{ + const USBDescIface* iface; + int g, i; + + if (!dev->Config) { // no configuration descriptor here, nothing to search + return nullptr; + } + for (g = 0; g < dev->Config->nif_groups; g++) { + for (i = 0; i < dev->config->if_groups[g].nif; i++) { + iface = &dev->config->if_groups[g].ifs[i]; + if (iface->bInterfaceNumber == nif && + iface->bAlternateSetting == alt) { + return iface; + } + } + } + for (i = 0; i < dev->config->nif; i++) { + iface = &dev->config->ifs[i]; + if (iface->bInterfaceNumber == nif && + iface->bAlternateSetting == alt) { + return iface; + } + } + return NULL; +} diff --git a/src/devices/usb/Hub.h b/src/devices/usb/Hub.h index 92d685871..001be4a39 100644 --- a/src/devices/usb/Hub.h +++ b/src/devices/usb/Hub.h @@ -74,7 +74,7 @@ class Hub final : public UsbPeripheral int request, int value, int index, int length, uint8_t* data); void UsbHub_HandleData(XboxDeviceState* dev, USBPacket* p); void UsbHub_HandleDestroy(XboxDeviceState* dev); - // TODO: perhaps these can be put in UsbPeripheral... + // TODO: perhaps these can be put in UsbPeripheral or USBDevice... // initialize the endpoints of this peripheral void UsbEpInit(); // destroy hub @@ -87,6 +87,16 @@ class Hub final : public UsbPeripheral const USBDesc* GetUsbDeviceDesc(XboxDeviceState* dev); // create a serial number for the device void CreateSerial(XboxDeviceState* dev); + // + void UsbDescInit(XboxDeviceState* dev); + // + void UsbDescSetDefaults(XboxDeviceState* dev); + // + int UsbDescSetConfig(XboxDeviceState* dev, int value); + // + int UsbDescSetInterface(XboxDeviceState* dev, int index, int value); + // + const USBDescIface* UsbDescFindInterface(XboxDeviceState* dev, int nif, int alt); }; extern Hub* g_HubObjArray[4]; diff --git a/src/devices/usb/OHCI.cpp b/src/devices/usb/OHCI.cpp index a2f152b1c..1d8c15728 100644 --- a/src/devices/usb/OHCI.cpp +++ b/src/devices/usb/OHCI.cpp @@ -178,30 +178,25 @@ #define USB_HZ 12000000 -#define USB_SPEED_LOW 0 -#define USB_SPEED_FULL 1 - #define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b))) #define OHCI_PAGE_MASK 0xFFFFF000 #define OHCI_OFFSET_MASK 0xFFF -typedef enum _USB_SPEED -{ - USB_SPEED_MASK_LOW = 1 << 0, - USB_SPEED_MASK_FULL = 1 << 1, -} -USB_SPEED; - - OHCI::OHCI(int Irq, USBDevice* UsbObj) { + int offset = 0; + m_IrqNum = Irq; m_UsbDevice = UsbObj; + if (m_IrqNum == 9) { + offset = 2; + } + for (int i = 0; i < 2; i++) { - m_UsbDevice->USB_RegisterPort(&m_Registers.RhPort[i].UsbPort, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); + m_UsbDevice->USB_RegisterPort(&m_Registers.RhPort[i].UsbPort, i + offset, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } OHCI_PacketInit(&m_UsbPacket); @@ -1423,7 +1418,7 @@ void OHCI::OHCI_Attach(USBPort* Port) port->HcRhPortStatus |= OHCI_PORT_CCS | OHCI_PORT_CSC; // update speed - if (port->UsbPort.Dev->speed == USB_SPEED_LOW) { + if (port->UsbPort.Dev->Speed == USB_SPEED_LOW) { port->HcRhPortStatus |= OHCI_PORT_LSDA; } else { diff --git a/src/devices/usb/OHCI.h b/src/devices/usb/OHCI.h index 98acc510d..0a7d0ad56 100644 --- a/src/devices/usb/OHCI.h +++ b/src/devices/usb/OHCI.h @@ -142,7 +142,6 @@ struct OHCI_Registers uint32_t HcRhDescriptorA; uint32_t HcRhDescriptorB; uint32_t HcRhStatus; - // For some reason, both XQEMU and OpenXbox set 4 ports per HC, for a total of 8 usb ports. OHCIPort RhPort[2]; // 2 ports per HC, for a total of 4 USB ports }; diff --git a/src/devices/usb/USBDevice.cpp b/src/devices/usb/USBDevice.cpp index 03c10316b..e91c1143c 100644 --- a/src/devices/usb/USBDevice.cpp +++ b/src/devices/usb/USBDevice.cpp @@ -60,10 +60,12 @@ void USBDevice::Init(unsigned int address) if (address == USB0_BASE) { m_HostController = new OHCI(1, this); + m_PciPath = "pci.0:02.0"; return; } m_HostController = new OHCI(9, this); + m_PciPath = "pci.0:03.0"; } uint32_t USBDevice::MMIORead(int barIndex, uint32_t addr, unsigned size) diff --git a/src/devices/usb/USBDevice.h b/src/devices/usb/USBDevice.h index 2cb661698..0343134ce 100644 --- a/src/devices/usb/USBDevice.h +++ b/src/devices/usb/USBDevice.h @@ -63,7 +63,9 @@ class USBDevice : public PCIDevice { // USBDevice-specific functions/variables // pointer to the host controller this device refers to - OHCI* m_HostController = nullptr; + OHCI* m_HostController; + // PCI path of this usb device + const char* m_PciPath; // register a port with the HC void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask); diff --git a/src/devices/usb/UsbCommon.h b/src/devices/usb/UsbCommon.h index 127f477d7..057c3872d 100644 --- a/src/devices/usb/UsbCommon.h +++ b/src/devices/usb/UsbCommon.h @@ -37,7 +37,7 @@ #ifndef USBCOMMON_H_ #define USBCOMMON_H_ -#include "Cxbx.h" +#include "CxbxCommon.h" #include "..\devices\video\queue.h" #include @@ -65,6 +65,16 @@ #define USB_TOKEN_IN 0x69 // device -> host #define USB_TOKEN_OUT 0xE1 // host -> device +#define USB_SPEED_LOW 0 +#define USB_SPEED_FULL 1 + + +typedef enum _USB_SPEED +{ + USB_SPEED_MASK_LOW = 1 << 0, + USB_SPEED_MASK_FULL = 1 << 1, +} +USB_SPEED; typedef enum USBPacketState { USB_PACKET_UNDEFINED = 0, @@ -80,6 +90,13 @@ struct USBPacket; struct XboxDeviceState; typedef const char* USBDescStrings[256]; +/* String descriptor */ +struct USBDescString { + uint8_t index; // index of this string descriptor + std::string str; // the string of this string descriptor + QLIST_ENTRY(USBDescString) next; +}; + struct USBDescOther { uint8_t length; const uint8_t* data; @@ -102,14 +119,15 @@ struct USBDescEndpoint { uint16_t wBytesPerInterval; }; +/* Interface descriptor */ struct USBDescIface { - uint8_t bInterfaceNumber; - uint8_t bAlternateSetting; - uint8_t bNumEndpoints; - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - uint8_t iInterface; + uint8_t bInterfaceNumber; // number of interface + uint8_t bAlternateSetting; // value used to select the alternate setting for the interface identified by bInterfaceNumber + uint8_t bNumEndpoints; // number of endpoints used by this interface (excluding endpoint zero) + uint8_t bInterfaceClass; // class code (assigned by the USB) + uint8_t bInterfaceSubClass; // subclass code (assigned by the USB) + uint8_t bInterfaceProtocol; // protocol code (assigned by the USB) + uint8_t iInterface; // index of string descriptor describing this interface uint8_t ndesc; USBDescOther* descs; @@ -131,12 +149,13 @@ struct USBDescIfaceAssoc { const USBDescIface* ifs; }; +/* Configuration descriptor */ struct USBDescConfig { - uint8_t bNumInterfaces; - uint8_t bConfigurationValue; - uint8_t iConfiguration; - uint8_t bmAttributes; - uint8_t bMaxPower; + uint8_t bNumInterfaces; // number of interfaces supported by this configuration + uint8_t bConfigurationValue; // value to use as an argument to the SetConfiguration() request to select this configuration + uint8_t iConfiguration; // index of string descriptor describing this configuration + uint8_t bmAttributes; // configuration characteristics + uint8_t bMaxPower; // maximum power consumption of the USB device in this configuration expressed in 2mA units /* grouped interfaces */ uint8_t nif_groups; @@ -147,25 +166,27 @@ struct USBDescConfig { const USBDescIface* ifs; }; +/* Device descriptor part 1 */ struct USBDescDevice { - uint16_t bcdUSB; - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - uint8_t bMaxPacketSize0; - uint8_t bNumConfigurations; - const USBDescConfig* confs; + uint16_t bcdUSB; // USB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H) + uint8_t bDeviceClass; // class code (assigned by the USB) + uint8_t bDeviceSubClass; // subclass code (assigned by the USB) + uint8_t bDeviceProtocol; // protocol code (assigned by the USB) + uint8_t bMaxPacketSize0; // maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid) + uint8_t bNumConfigurations; // number of possible configurations + const USBDescConfig* confs; // configuration descriptor in use USBDescDevice(bool bDefault); ~USBDescDevice(); }; +/* Device descriptor part 2 */ struct USBDescID { - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice; - uint8_t iManufacturer; - uint8_t iProduct; - uint8_t iSerialNumber; // index of string descriptor + uint16_t idVendor; // vendor ID (assigned by the USB) + uint16_t idProduct; // product ID (assigned by the manufacturer) + uint16_t bcdDevice; // device release number in binary-coded decimal + uint8_t iManufacturer; // index of string descriptor describing manufacturer + uint8_t iProduct; // index of string descriptor describing product + uint8_t iSerialNumber; // index of string descriptor describing the device’s serial number }; /* Global USB Descriptor struct */ @@ -186,23 +207,21 @@ struct USBEndpoint int MaxPacketSize; bool Pipeline; bool Halted; // indicates that the endpoint is halted - XboxDeviceState* Dev; // device this endpoint belongs to - QTAILQ_HEAD(, USBPacket) Queue; // queue of packets to this endpoint + XboxDeviceState* Dev; // device this endpoint belongs to + QTAILQ_HEAD(, USBPacket) Queue; // queue of packets to this endpoint }; /* definition of an Xbox usb device */ struct XboxDeviceState { - USBPort* Port; // usb port struct of this device - int PortPath; // port index to which this device is attached to - char* Serial; - uint32_t flags; - USBDeviceClass* klass; // usb class struct of this device - - // Actual connected speed - int speed; - // Supported speeds, not in info because it may be variable (hostdevs) - int speedmask; + USBPort* Port; // usb port struct of this device + int PortPath; // port index to which this device is attached to + char* Serial; + uint32_t flags; + USBDeviceClass* klass; // usb class struct of this device + + int Speed; // actual connected speed + int SpeedMask; // supported speeds, not in info because it may be variable (hostdevs) uint8_t Addr; // device function address std::string ProductDesc; // the friendly name of this device int Attached; // device is attached @@ -219,15 +238,15 @@ struct XboxDeviceState USBEndpoint EP_in[USB_MAX_ENDPOINTS]; // endpoints for OUT tokens USBEndpoint EP_out[USB_MAX_ENDPOINTS]; // endpoints for IN tokens - QLIST_HEAD(, USBDescString) Strings; - const USBDesc* usb_desc; // Overrides class usb_desc if not NULL - const USBDescDevice *device; + QLIST_HEAD(, USBDescString) Strings; // strings of the string descriptor + const USBDesc* UsbDesc; // Overrides class usb_desc if not NULL + const USBDescDevice* Device; // device descriptor part 1 - int configuration; - int ninterfaces; - int altsetting[USB_MAX_INTERFACES]; - const USBDescConfig *config; - const USBDescIface *ifaces[USB_MAX_INTERFACES]; + int Configuration; // number of the selected configuration descriptor + int NumInterfaces; // number of available interface descriptors + int AltSetting[USB_MAX_INTERFACES]; // + const USBDescConfig* Config; // configuration descriptor in use + const USBDescIface* Ifaces[USB_MAX_INTERFACES]; }; struct USBCombinedPacket { @@ -260,8 +279,8 @@ struct USBPacket struct USBPort { XboxDeviceState* Dev; // usb device (if present) int SpeedMask; // usb speeds supported - int HubCount; // number of hubs attached - char Path[16]; // the number of the port + int HubCount; // number of hubs chained + char Path[16]; // the number of the port + 1, used to create a serial number for this device int PortIndex; // internal port index against this HC }; @@ -310,7 +329,7 @@ struct USBDeviceClass // has been unlinked / stopped. Optional may be NULL. std::function ep_stopped; - const char* product_desc; + const char* product_desc; // friendly name of the device const USBDesc* usb_desc; // device descriptor };