Sync code with ergo720's branch up to commit 549195f

This commit is contained in:
StrikerX3 2018-07-05 20:22:08 -03:00
parent 8fc9059dd1
commit ef1f03a6df
8 changed files with 988 additions and 296 deletions

View file

@ -61,11 +61,7 @@ void IoVecAdd(IOVector* qiov, void* base, size_t len);
size_t IoVecTobuffer(const IoVec* iov, const unsigned int iov_cnt, size_t offset, void *buf, size_t bytes);
size_t IoVecFromBuffer(const IoVec* iov, unsigned int iov_cnt, size_t offset, void* buf, size_t bytes);
// Calculate a struct base address from a pointer to a member of it
#ifndef container_of
#define container_of(address, type, field) ((type *)(\
(int8_t*)(address) - \
(uint32_t)(&((type *)0)->field)))
#endif
#define GET_WORD_LOW(value) (uint8_t)((value) & 0xFF)
#define GET_WORD_HIGH(value) (uint8_t)(((value) >> 8) & 0xFF)
}

View file

@ -199,7 +199,7 @@ OHCI::OHCI(Cpu* cpu, int Irq, USBPCIDevice* UsbObj)
ops->attach = std::bind(&OHCI::OHCI_Attach, this, _1);
ops->detach = std::bind(&OHCI::OHCI_Detach, this, _1);
ops->child_detach = std::bind(&OHCI::OHCI_ChildDetach, this, nullptr, _2);
ops->child_detach = std::bind(&OHCI::OHCI_ChildDetach, this, _1);
ops->wakeup = std::bind(&OHCI::OHCI_Wakeup, this, _1);
ops->complete = std::bind(&OHCI::OHCI_AsyncCompletePacket, this, _1, _2);
}
@ -1448,7 +1448,7 @@ void OHCI::OHCI_Attach(USBPort* Port)
}
}
void OHCI::OHCI_ChildDetach(USBPort* port, XboxDeviceState* child) {
void OHCI::OHCI_ChildDetach(XboxDeviceState* child) {
OHCI_AsyncCancelDevice(child);
}

View file

@ -263,7 +263,7 @@ private:
// see USBPortOps struct for info
void OHCI_Attach(USBPort* Port);
void OHCI_Detach(USBPort* Port);
void OHCI_ChildDetach(USBPort* port, XboxDeviceState* child);
void OHCI_ChildDetach(XboxDeviceState* child);
void OHCI_Wakeup(USBPort* port1);
void OHCI_AsyncCompletePacket(USBPort* port, USBPacket* packet);
};

View file

@ -72,6 +72,61 @@ namespace openxbox {
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
#define USB_DEVICE_SELF_POWERED 0
#define USB_DEVICE_REMOTE_WAKEUP 1
#define USB_TYPE_MASK (0x03 << 5)
#define USB_TYPE_STANDARD (0x00 << 5)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_TYPE_VENDOR (0x02 << 5)
#define USB_TYPE_RESERVED (0x03 << 5)
#define USB_RECIP_MASK 0x1F
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03
#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
#define VendorDeviceRequest ((USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
#define VendorDeviceOutRequest ((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_DEVICE)<<8)
#define InterfaceRequest \
((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
#define InterfaceOutRequest \
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
#define ClassInterfaceRequest \
((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
#define ClassInterfaceOutRequest \
((USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
#define VendorInterfaceRequest \
((USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE)<<8)
#define VendorInterfaceOutRequest \
((USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE)<<8)
#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
#define EndpointOutRequest \
((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIG 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
typedef enum _USB_SPEED {
USB_SPEED_MASK_LOW = 1 << 0,
USB_SPEED_MASK_FULL = 1 << 1,
@ -93,8 +148,6 @@ struct USBPort;
struct USBDeviceClass;
struct XboxDeviceState;
typedef const char* USBDescStrings[256];
/* String descriptor */
struct USBDescString {
uint8_t index; // index of this string descriptor
@ -102,6 +155,7 @@ struct USBDescString {
QLIST_ENTRY(USBDescString) next;
};
// Device-specific class descriptors, if any. No idea if some Xbox devices use this but, if not, this can be removed
struct USBDescOther {
uint8_t length;
const uint8_t *data;
@ -116,8 +170,11 @@ struct USBDescEndpoint {
uint8_t bRefresh; // for audio devices only: the rate at which synchronization feedback is provided
uint8_t bSynchAddress; // for audio devices only: the address of the synchronization endpoint
uint8_t is_audio; /* has bRefresh + bSynchAddress */
uint8_t* extra;
uint8_t is_audio; // has bRefresh + bSynchAddress
uint8_t* extra; // class-specific descriptors (if any) associated with this endpoint
// Dropped from XQEMU the parameters bMaxBurst, bmAttributes_super and wBytesPerInterval because those are only defined for
// superspeed (usb 3.0) devices in the superspeed endpoint companion
};
/* Interface descriptor */
@ -130,8 +187,8 @@ struct USBDescIface {
uint8_t bInterfaceProtocol; // protocol code (assigned by the USB)
uint8_t iInterface; // index of string descriptor describing this interface
uint8_t ndesc;
USBDescOther* descs;
uint8_t ndesc; // number of device-specific class descriptors (if any)
USBDescOther* descs; // pointer to the extra class descriptors
USBDescEndpoint* eps; // endpoints supported by this interface
USBDescIface(bool bDefault);
~USBDescIface();
@ -187,6 +244,64 @@ struct USBDesc {
USBDesc(bool bDefault);
};
#pragma pack(1)
// Binary representation of the descriptors
// Dropped from XQEMU usb 2.0 and 3.0 only descriptors
struct USBDescriptor {
uint8_t bLength;
uint8_t bDescriptorType;
union {
struct {
uint8_t bcdUSB_lo;
uint8_t bcdUSB_hi;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint8_t idVendor_lo;
uint8_t idVendor_hi;
uint8_t idProduct_lo;
uint8_t idProduct_hi;
uint8_t bcdDevice_lo;
uint8_t bcdDevice_hi;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} device; // device descriptor
struct {
uint8_t wTotalLength_lo;
uint8_t wTotalLength_hi;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} config; // configuration descriptor
struct {
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} iface; // interface descriptor
struct {
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint8_t wMaxPacketSize_lo;
uint8_t wMaxPacketSize_hi;
uint8_t bInterval;
uint8_t bRefresh; // only audio ep
uint8_t bSynchAddress; // only audio ep
} endpoint; // endpoint descriptor
} u;
};
#pragma pack()
/* USB endpoint */
struct USBEndpoint {
uint8_t Num; // endpoint number
@ -208,25 +323,25 @@ struct XboxDeviceState {
uint32_t flags;
USBDeviceClass* klass; // usb class struct of this device
int Speed; // actual connected speed
int Speed; // actual speed of the connected device
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
int32_t State; // current state of device
uint8_t SetupBuffer[8]; // holds the IoVec structs copied (control transfers only?)
uint8_t data_buf[4096];
uint8_t SetupBuffer[8]; // setup packet buffer - 8 bytes (control transfers only)
uint8_t DataBuffer[4096]; // buffer where to write the data requested during usb requests
int32_t RemoteWakeup; // wakeup flag
int32_t SetupState; // result of a setup tken processing operation
int32_t SetupLength; // number of bytes to transfer as specified by a setup token
int32_t SetupLength; // this field specifies the length of the data transferred during the second phase of the control transfer
int32_t SetupIndex; // index of the parameter in a setup token?
USBEndpoint EP_ctl; // endpoints for SETUP tokens
USBEndpoint EP_in[USB_MAX_ENDPOINTS]; // endpoints for OUT tokens
USBEndpoint EP_out[USB_MAX_ENDPOINTS]; // endpoints for IN tokens
QLIST_HEAD(, USBDescString) Strings; // strings of the string descriptor
QLIST_HEAD(, USBDescString) Strings; // strings of the string descriptors
const USBDesc* UsbDesc; // Overrides class usb_desc if not nullptr
const USBDescDevice* Device; // device descriptor part 1
@ -254,7 +369,7 @@ struct USBPacket {
bool ShortNotOK; // the bufferRounding mode of the TD for this packet
bool IntReq; // whether or not to generate an interrupt for this packet (DelayInterrupt of the TD is zero)
int Status; // USB_RET_* status code
int ActualLength; // before copy: offset inside IoVec structs; after copy: number of bytes actually transferred
int ActualLength; // number of bytes actually written to DataBuffer
// Internal use by the USB layer
USBPacketState State;
USBCombinedPacket* Combined;
@ -269,7 +384,7 @@ struct USBPortOps {
* This gets called when a device downstream from the device attached to
* the port (attached through a hub) gets detached.
*/
std::function<void(USBPort* port, XboxDeviceState* child)> child_detach;
std::function<void(XboxDeviceState* child)> child_detach;
std::function<void(USBPort* port)> wakeup;
/*
* Note that port->dev will be different then the device from which
@ -285,7 +400,7 @@ struct USBPort {
int SpeedMask; // usb speeds supported
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
int PortIndex; // internal port index
};
/* Struct which stores general functions/variables regarding the peripheral */
@ -336,14 +451,4 @@ struct USBDeviceClass {
const USBDesc* usb_desc; // device descriptor
};
/* Abstract class representing a usb peripheral */
class UsbPeripheral {
protected:
USBDeviceClass * m_pPeripheralFuncStruct;
XboxDeviceState* m_pDeviceStruct;
virtual int Init(int pport) = 0;
};
}

View file

@ -111,8 +111,6 @@ USBDescDevice::~USBDescDevice() {
static const USBDescDevice desc_device_hub(true);
static USBDescStrings desc_strings = { nullptr, "Cxbx-Reloaded", "Cxbx-Reloaded USB Hub", "314159" };
USBDesc::USBDesc(bool bDefault) {
std::memset(this, 0, sizeof(USBDesc));
if (bDefault) {
@ -123,25 +121,24 @@ USBDesc::USBDesc(bool bDefault) {
id.iProduct = STR_PRODUCT;
id.iSerialNumber = STR_SERIALNUMBER;
full = &desc_device_hub;
str = desc_strings;
}
}
static const USBDesc desc_hub(true);
int Hub::Init(int pport) {
ClassInitFn();
UsbEpInit();
int rc = UsbClaimPort(pport);
XboxDeviceState* dev = ClassInitFn();
m_UsbDev->USB_EpInit(dev);
int rc = UsbHubClaimPort(dev, pport);
if (rc != 0) {
return rc;
}
rc = m_UsbDev->USB_DeviceInit(m_pDeviceStruct);
rc = m_UsbDev->USB_DeviceInit(dev);
if (rc != 0) {
UsbReleasePort(m_pDeviceStruct);
UsbHubReleasePort(dev);
return rc;
}
m_UsbDev->USB_DeviceAttach(m_pDeviceStruct);
m_UsbDev->USB_DeviceAttach(dev);
return 0;
}
@ -150,17 +147,17 @@ Hub::~Hub() {
delete m_HubState->ports[0].port.Operations;
delete m_HubState;
m_pPeripheralFuncStruct = nullptr;
m_pDeviceStruct = nullptr;
m_HubState = nullptr;
}
void Hub::ClassInitFn() {
XboxDeviceState* Hub::ClassInitFn() {
m_pPeripheralFuncStruct = new USBDeviceClass();
m_HubState = new USBHubState();
m_pDeviceStruct = &m_HubState->dev;
XboxDeviceState* dev = &m_HubState->dev;
m_pDeviceStruct->ProductDesc = "Cxbx-Reloaded USB Hub";
QLIST_INIT(&m_pDeviceStruct->Strings);
m_pDeviceStruct->klass = m_pPeripheralFuncStruct;
dev->ProductDesc = "Cxbx-Reloaded USB Hub";
QLIST_INIT(&dev->Strings);
dev->klass = m_pPeripheralFuncStruct;
{
using namespace std::placeholders;
@ -171,66 +168,34 @@ void Hub::ClassInitFn() {
m_pPeripheralFuncStruct->handle_control = std::bind(&Hub::UsbHub_HandleControl, this, _1, _2, _3, _4, _5, _6, _7);
m_pPeripheralFuncStruct->handle_data = std::bind(&Hub::UsbHub_HandleData, this, _1, _2);
m_pPeripheralFuncStruct->handle_destroy = std::bind(&Hub::UsbHub_HandleDestroy, this, _1);
m_pPeripheralFuncStruct->product_desc = m_pDeviceStruct->ProductDesc.c_str();
m_pPeripheralFuncStruct->product_desc = dev->ProductDesc.c_str();
m_pPeripheralFuncStruct->usb_desc = &desc_hub;
}
return dev;
}
void Hub::UsbEpInit() {
UsbEpReset();
QTAILQ_INIT(&m_pDeviceStruct->EP_ctl.Queue);
for (int ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
QTAILQ_INIT(&m_pDeviceStruct->EP_in[ep].Queue);
QTAILQ_INIT(&m_pDeviceStruct->EP_out[ep].Queue);
}
}
void Hub::UsbEpReset() {
m_pDeviceStruct->EP_ctl.Num = 0;
m_pDeviceStruct->EP_ctl.Type = USB_ENDPOINT_XFER_CONTROL;
m_pDeviceStruct->EP_ctl.IfNum = 0;
m_pDeviceStruct->EP_ctl.MaxPacketSize = 64;
m_pDeviceStruct->EP_ctl.Dev = m_pDeviceStruct;
m_pDeviceStruct->EP_ctl.Pipeline = false;
for (int ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
m_pDeviceStruct->EP_in[ep].Num = ep + 1;
m_pDeviceStruct->EP_out[ep].Num = ep + 1;
m_pDeviceStruct->EP_in[ep].pid = USB_TOKEN_IN;
m_pDeviceStruct->EP_out[ep].pid = USB_TOKEN_OUT;
m_pDeviceStruct->EP_in[ep].Type = USB_ENDPOINT_XFER_INVALID;
m_pDeviceStruct->EP_out[ep].Type = USB_ENDPOINT_XFER_INVALID;
m_pDeviceStruct->EP_in[ep].IfNum = USB_INTERFACE_INVALID;
m_pDeviceStruct->EP_out[ep].IfNum = USB_INTERFACE_INVALID;
m_pDeviceStruct->EP_in[ep].MaxPacketSize = 0;
m_pDeviceStruct->EP_out[ep].MaxPacketSize = 0;
m_pDeviceStruct->EP_in[ep].Dev = m_pDeviceStruct;
m_pDeviceStruct->EP_out[ep].Dev = m_pDeviceStruct;
m_pDeviceStruct->EP_in[ep].Pipeline = false;
m_pDeviceStruct->EP_out[ep].Pipeline = false;
}
}
int Hub::UsbClaimPort(int pport) {
int Hub::UsbHubClaimPort(XboxDeviceState* dev, int pport) {
int usb_port;
assert(m_pDeviceStruct->Port == nullptr);
assert(dev->Port == nullptr);
if (pport > 4 || pport < 1) { return -1; };
usb_port = PlayerToUsbArray[pport];
if (usb_port > 2) {
m_UsbDev = g_USB0; // FIXME: how to retrieve these?
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 3, m_pDeviceStruct);
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 3, dev);
}
else {
m_UsbDev = g_USB1; // FIXME: how to retrieve these?
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 1, m_pDeviceStruct);
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 1, dev);
}
return 0;
}
void Hub::UsbReleasePort(XboxDeviceState* dev) {
void Hub::UsbHubReleasePort(XboxDeviceState* dev) {
USBPort * port = dev->Port;
assert(port != nullptr);
@ -249,8 +214,10 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev) {
return -1;
}
CreateSerial(dev);
UsbDescInit(dev);
m_UsbDev->USB_CreateSerial(dev, "314159");
m_UsbDev->USBDesc_SetString(dev, STR_MANUFACTURER, "Cxbx-Reloaded");
m_UsbDev->USBDesc_SetString(dev, STR_PRODUCT, "Cxbx-Reloaded USB Hub");
m_UsbDev->USBDesc_Init(dev);
m_HubState->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 1);
ops = new USBPortOps();
@ -259,7 +226,7 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev) {
ops->attach = std::bind(&Hub::UsbHub_Attach, this, _1);
ops->detach = std::bind(&Hub::UsbHub_Detach, this, _1);
ops->child_detach = std::bind(&Hub::UsbHub_ChildDetach, this, _1, _2);
ops->child_detach = std::bind(&Hub::UsbHub_ChildDetach, this, _1);
ops->wakeup = std::bind(&Hub::UsbHub_Wakeup, this, _1);
ops->complete = std::bind(&Hub::UsbHub_Complete, this, _1, _2);
}
@ -273,6 +240,23 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev) {
return 0;
}
XboxDeviceState* Hub::UsbHub_FindDevice(XboxDeviceState* dev, uint8_t addr) {
USBHubPort * port;
XboxDeviceState * downstream;
for (int i = 0; i < NUM_PORTS; i++) {
port = &m_HubState->ports[i];
if (!(port->wPortStatus & PORT_STAT_ENABLE)) {
continue;
}
downstream = m_UsbDev->USB_FindDevice(&port->port, addr);
if (downstream != nullptr) {
return downstream;
}
}
return nullptr;
}
void Hub::UsbHub_HandleReset() {
USBHubPort* port;
@ -289,181 +273,159 @@ void Hub::UsbHub_HandleReset() {
}
}
}
void Hub::UsbHub_HandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) {
USBHubState * s = (USBHubState *)dev;
int ret;
ret = m_UsbDev->USBDesc_HandleControl(dev, p, request, value, index, length, data);
if (ret >= 0) {
return;
}
/*
* From XQEMU:
* This function creates a serial number for a usb device.
* The serial number should:
* (a) Be unique within the emulator.
* (b) Be constant, so you don't get a new one each
* time the guest is started.
* So we are using the physical location to generate a serial number
* from it. It has three pieces: First a fixed, device-specific
* prefix. Second the device path of the host controller (which is
* the pci address in most cases). Third the physical port path.
* Results in serial numbers like this: "314159-0000:00:1d.7-3".
*/
void Hub::CreateSerial(XboxDeviceState* dev) {
const USBDesc* desc = GetUsbDeviceDesc(dev);
int index = desc->id.iSerialNumber;
USBDescString* s;
char serial[64];
char* path;
int dst;
assert(index != 0 && desc->str[index] != NULL);
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) {
switch (request) {
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == 0 && index != 0x81) { /* clear ep halt */
goto fail;
}
break;
/* usb specific requests */
case GetHubStatus:
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 0;
p->actual_length = 4;
break;
case GetPortStatus:
{
unsigned int n = index - 1;
USBHubPort * port;
if (n >= NUM_PORTS) {
goto fail;
}
port = &s->ports[n];
trace_usb_hub_get_port_status(s->dev.addr, index,
port->wPortStatus,
port->wPortChange);
data[0] = port->wPortStatus;
data[1] = port->wPortStatus >> 8;
data[2] = port->wPortChange;
data[3] = port->wPortChange >> 8;
p->actual_length = 4;
}
break;
case SetHubFeature:
case ClearHubFeature:
if (value != 0 && value != 1) {
goto fail;
}
break;
case SetPortFeature:
{
unsigned int n = index - 1;
USBHubPort * port;
USBDevice * dev;
trace_usb_hub_set_port_feature(s->dev.addr, index, feature_name(value));
if (n >= NUM_PORTS) {
goto fail;
}
port = &s->ports[n];
dev = port->port.dev;
switch (value) {
case PORT_SUSPEND:
port->wPortStatus |= PORT_STAT_SUSPEND;
break;
case PORT_RESET:
if (dev && dev->attached) {
usb_device_reset(dev);
port->wPortChange |= PORT_STAT_C_RESET;
/* set enable bit */
port->wPortStatus |= PORT_STAT_ENABLE;
usb_wakeup(s->intr, 0);
}
break;
case PORT_POWER:
break;
default:
goto fail;
}
}
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->UsbDesc) {
return dev->UsbDesc;
}
return klass->usb_desc;
}
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:
break;
case GetHubDescriptor:
{
dev->Device = desc->full;
unsigned int n, limit, var_hub_size = 0;
memcpy(data, qemu_hub_hub_descriptor,
sizeof(qemu_hub_hub_descriptor));
data[2] = NUM_PORTS;
/* fill DeviceRemovable bits */
limit = ((NUM_PORTS + 1 + 7) / 8) + 7;
for (n = 7; n < limit; n++) {
data[n] = 0x00;
var_hub_size++;
}
/* fill PortPwrCtrlMask bits */
limit = limit + ((NUM_PORTS + 7) / 8);
for (; n < limit; n++) {
data[n] = 0xff;
var_hub_size++;
} p->actual_length = sizeof(qemu_hub_hub_descriptor) + var_hub_size;
data[0] = p->actual_length;
break;
}
default:
log_warning("Unknown speed parameter %d set in %s", dev->ProductDesc.c_str());
fail:
p->status = USB_RET_STALL;
break;
}
UsbDescSetConfig(dev, 0);
}
int Hub::UsbDescSetConfig(XboxDeviceState* dev, int value) {
int i;
void Hub::UsbHub_Attach(USBPort* port1) {
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
if (value == 0) { // default configuration
dev->Configuration = 0;
dev->NumInterfaces = 0;
dev->Config = nullptr;
port->wPortStatus |= PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->port.Dev->Speed == USB_SPEED_LOW) {
port->wPortStatus |= PORT_STAT_LOW_SPEED;
}
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;
}
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
}
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;
m_UsbDev->USB_Wakeup(m_HubState->intr);
}
int Hub::UsbDescSetInterface(XboxDeviceState* dev, int index, int value) {
const USBDescIface* iface;
int old;
void Hub::UsbHub_Detach(USBPort* port1) {
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
iface = UsbDescFindInterface(dev, index, value);
if (iface == nullptr) {
return -1;
m_UsbDev->USB_Wakeup(m_HubState->intr);
// Let upstream know the device on this port is gone
m_HubState->dev.Port->Operations->child_detach(port1->Dev);
port->wPortStatus &= ~PORT_STAT_CONNECTION;
port->wPortChange |= PORT_STAT_C_CONNECTION;
if (port->wPortStatus & PORT_STAT_ENABLE) {
port->wPortStatus &= ~PORT_STAT_ENABLE;
port->wPortChange |= PORT_STAT_C_ENABLE;
}
old = dev->AltSetting[index];
dev->AltSetting[index] = value;
dev->Ifaces[index] = iface;
UsbDescEpInit(dev);
if (old != value) {
m_UsbDev->USB_DeviceSetInterface(dev, index, old, value);
}
return 0;
m_UsbDev->USB_Wakeup(m_HubState->intr);
}
const USBDescIface* Hub::UsbDescFindInterface(XboxDeviceState* dev, int nif, int alt) {
const USBDescIface* iface;
int i;
if (!dev->Config) { // no configuration descriptor here, nothing to search
return nullptr;
}
for (i = 0; i < dev->Config->nif; i++) { // find the desired interface
iface = &dev->Config->ifs[i];
if (iface->bInterfaceNumber == nif &&
iface->bAlternateSetting == alt) {
return iface;
}
}
return nullptr; // not found
void Hub::UsbHub_ChildDetach(XboxDeviceState* child) {
// Pass along to upstream
m_HubState->dev.Port->Operations->child_detach(child);
}
void Hub::UsbDescEpInit(XboxDeviceState* dev) {
const USBDescIface *iface;
int i, e, pid, ep;
void Hub::UsbHub_Wakeup(USBPort* port1) {
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
UsbEpInit(); // reset endpoints (because we changed descriptors in use?)
for (i = 0; i < dev->NumInterfaces; i++) {
iface = dev->Ifaces[i];
if (iface == nullptr) {
continue;
}
for (e = 0; e < iface->bNumEndpoints; e++) {
// From the standard:
// "bEndpointAddress:
// Bit 3...0: The endpoint number
// Bit 6...4: Reserved, reset to zero
// Bit 7: Direction -> 0 = OUT endpoint, 1 = IN endpoint
// bmAttributes:
// Bit 1..0: Transfer Type
// 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt. All other bits are reserved"
pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = iface->eps[e].bEndpointAddress & 0xF;
m_UsbDev->USB_EPsetType(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
m_UsbDev->USB_EPsetIfnum(dev, pid, ep, iface->bInterfaceNumber);
m_UsbDev->USB_EPsetMaxPacketSize(dev, pid, ep, iface->eps[e].wMaxPacketSize);
}
if (port->wPortStatus & PORT_STAT_SUSPEND) {
port->wPortChange |= PORT_STAT_C_SUSPEND;
m_UsbDev->USB_Wakeup(m_HubState->intr);
}
}
void Hub::UsbHub_Complete(USBPort* port, USBPacket* packet) {
// Just pass it along to upstream
m_HubState->dev.Port->Operations->complete(m_HubState->dev.Port, packet);
}
}

View file

@ -81,10 +81,10 @@ struct USBHubState {
};
/* Class which implements a usb hub */
class Hub final : public UsbPeripheral {
class Hub {
public:
// initialize this peripheral
int Init(int pport) override;
int Init(int pport);
// destructor
~Hub();
@ -94,9 +94,11 @@ private:
USBPCIDevice* m_UsbDev = nullptr;
// hub state
USBHubState* m_HubState = nullptr;
// hub class functions
USBDeviceClass* m_pPeripheralFuncStruct = nullptr;
// initialize various member variables/functions
void ClassInitFn();
XboxDeviceState* ClassInitFn();
// see USBDeviceClass for comments about these functions
int UsbHub_Initfn(XboxDeviceState* dev);
XboxDeviceState* UsbHub_FindDevice(XboxDeviceState* dev, uint8_t addr);
@ -108,34 +110,13 @@ private:
// see USBPortOps struct for info
void UsbHub_Attach(USBPort* port1);
void UsbHub_Detach(USBPort* port1);
void UsbHub_ChildDetach(USBPort* port1, XboxDeviceState* child);
void UsbHub_ChildDetach(XboxDeviceState* child);
void UsbHub_Wakeup(USBPort* port1);
void UsbHub_Complete(USBPort* port, USBPacket* packet);
// TODO: perhaps these can be put in UsbPeripheral or USBDevice...
// initialize the endpoints of this peripheral
void UsbEpInit();
// reset all endpoints of this peripheral
void UsbEpReset();
// reserve a usb port for this hub
int UsbClaimPort(int port);
//
void UsbReleasePort(XboxDeviceState* dev);
// get device descriptor
const USBDesc* GetUsbDeviceDesc(XboxDeviceState* dev);
// create a serial number for the device
void CreateSerial(XboxDeviceState* dev);
// start descriptors initialization
void UsbDescInit(XboxDeviceState* dev);
// set the descriptors to use for this device
void UsbDescSetDefaults(XboxDeviceState* dev);
// set the configuration to use
int UsbDescSetConfig(XboxDeviceState* dev, int value);
// set the interface to use
int UsbDescSetInterface(XboxDeviceState* dev, int index, int value);
// find the interface to use
const USBDescIface* UsbDescFindInterface(XboxDeviceState* dev, int nif, int alt);
// setup endpoints and their descriptors
void UsbDescEpInit(XboxDeviceState* dev);
int UsbHubClaimPort(XboxDeviceState* dev, int port);
// free the usb port used by this hub
void UsbHubReleasePort(XboxDeviceState* dev);
};
extern Hub* g_HubObjArray[4];

View file

@ -116,15 +116,6 @@ void USBPCIDevice::USB_PortReset(USBPort* Port) {
USB_DeviceReset(dev);
}
void USBPCIDevice::USB_Detach(USBPort* Port) {
XboxDeviceState* dev = Port->Dev;
assert(dev != nullptr);
assert(dev->State != USB_STATE_NOTATTACHED);
m_HostController->OHCI_Detach(Port);
dev->State = USB_STATE_NOTATTACHED;
}
void USBPCIDevice::USB_Attach(USBPort* Port) {
XboxDeviceState* dev = Port->Dev;
@ -136,6 +127,23 @@ void USBPCIDevice::USB_Attach(USBPort* Port) {
USB_DeviceHandleAttach(dev);
}
void USBPCIDevice::USB_Detach(USBPort* Port) {
XboxDeviceState* dev = Port->Dev;
assert(dev != nullptr);
assert(dev->State != USB_STATE_NOTATTACHED);
Port->Operations->detach(Port);
dev->State = USB_STATE_NOTATTACHED;
}
void USBPCIDevice::USB_Wakeup(USBEndpoint* ep) {
XboxDeviceState* dev = ep->Dev;
if (dev->RemoteWakeup && dev->Port && dev->Port->Operations->wakeup) {
dev->Port->Operations->wakeup(dev->Port);
}
}
void USBPCIDevice::USB_DeviceReset(XboxDeviceState* dev) {
if (dev == nullptr || !dev->Attached) {
return;
@ -312,17 +320,17 @@ void USBPCIDevice::USB_DoParameter(XboxDeviceState* s, USBPacket* p) {
value = (s->SetupBuffer[3] << 8) | s->SetupBuffer[2];
index = (s->SetupBuffer[5] << 8) | s->SetupBuffer[4];
if (s->SetupLength > sizeof(s->data_buf)) {
log_debug("USB: ctrl buffer too small (%d > %zu)\n", s->SetupLength, sizeof(s->data_buf));
if (s->SetupLength > sizeof(s->DataBuffer)) {
log_debug("USB: ctrl buffer too small (%d > %zu)\n", s->SetupLength, sizeof(s->DataBuffer));
p->Status = USB_RET_STALL;
return;
}
if (p->Pid == USB_TOKEN_OUT) {
USB_PacketCopy(p, s->data_buf, s->SetupLength);
USB_PacketCopy(p, s->DataBuffer, s->SetupLength);
}
USB_DeviceHandleControl(s, p, request, value, index, s->SetupLength, s->data_buf);
USB_DeviceHandleControl(s, p, request, value, index, s->SetupLength, s->DataBuffer);
if (p->Status == USB_RET_ASYNC) {
return;
}
@ -332,7 +340,7 @@ void USBPCIDevice::USB_DoParameter(XboxDeviceState* s, USBPacket* p) {
}
if (p->Pid == USB_TOKEN_IN) {
p->ActualLength = 0;
USB_PacketCopy(p, s->data_buf, s->SetupLength);
USB_PacketCopy(p, s->DataBuffer, s->SetupLength);
}
}
@ -363,7 +371,7 @@ void USBPCIDevice::USB_DoTokenSetup(XboxDeviceState* s, USBPacket* p) {
index = (s->SetupBuffer[5] << 8) | s->SetupBuffer[4];
if (s->SetupBuffer[0] & USB_DIR_IN) {
USB_DeviceHandleControl(s, p, request, value, index, s->SetupLength, s->data_buf);
USB_DeviceHandleControl(s, p, request, value, index, s->SetupLength, s->DataBuffer);
if (p->Status == USB_RET_ASYNC) {
s->SetupState = SETUP_STATE_SETUP;
}
@ -377,8 +385,8 @@ void USBPCIDevice::USB_DoTokenSetup(XboxDeviceState* s, USBPacket* p) {
s->SetupState = SETUP_STATE_DATA;
}
else {
if (s->SetupLength > sizeof(s->data_buf)) {
log_debug("USB: ctrl buffer too small (%d > %zu)\n", s->SetupLength, sizeof(s->data_buf));
if (s->SetupLength > sizeof(s->DataBuffer)) {
log_debug("USB: ctrl buffer too small (%d > %zu)\n", s->SetupLength, sizeof(s->DataBuffer));
p->Status = USB_RET_STALL;
return;
}
@ -405,7 +413,7 @@ void USBPCIDevice::DoTokenIn(XboxDeviceState* s, USBPacket* p) {
switch (s->SetupState) {
case SETUP_STATE_ACK:
if (!(s->SetupBuffer[0] & USB_DIR_IN)) {
USB_DeviceHandleControl(s, p, request, value, index, s->SetupLength, s->data_buf);
USB_DeviceHandleControl(s, p, request, value, index, s->SetupLength, s->DataBuffer);
if (p->Status == USB_RET_ASYNC) {
return;
}
@ -420,7 +428,7 @@ void USBPCIDevice::DoTokenIn(XboxDeviceState* s, USBPacket* p) {
if (len > p->IoVec.Size) {
len = p->IoVec.Size;
}
USB_PacketCopy(p, s->data_buf + s->SetupIndex, len);
USB_PacketCopy(p, s->DataBuffer + s->SetupIndex, len);
s->SetupIndex += len;
if (s->SetupIndex >= s->SetupLength) {
s->SetupState = SETUP_STATE_ACK;
@ -456,7 +464,7 @@ void USBPCIDevice::DoTokenOut(XboxDeviceState* s, USBPacket* p) {
if (len > p->IoVec.Size) {
len = p->IoVec.Size;
}
USB_PacketCopy(p, s->data_buf + s->SetupIndex, len);
USB_PacketCopy(p, s->DataBuffer + s->SetupIndex, len);
s->SetupIndex += len;
if (s->SetupIndex >= s->SetupLength) {
s->SetupState = SETUP_STATE_ACK;
@ -626,4 +634,605 @@ void USBPCIDevice::USB_DeviceAttach(XboxDeviceState* dev) {
USB_Attach(port);
}
void USBPCIDevice::USB_EpInit(XboxDeviceState* dev) {
USB_EpReset(dev);
QTAILQ_INIT(&dev->EP_ctl.Queue);
for (int ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
QTAILQ_INIT(&dev->EP_in[ep].Queue);
QTAILQ_INIT(&dev->EP_out[ep].Queue);
}
}
void USBPCIDevice::USB_EpReset(XboxDeviceState* dev) {
dev->EP_ctl.Num = 0;
dev->EP_ctl.Type = USB_ENDPOINT_XFER_CONTROL;
dev->EP_ctl.IfNum = 0;
dev->EP_ctl.MaxPacketSize = 64;
dev->EP_ctl.Dev = dev;
dev->EP_ctl.Pipeline = false;
for (int ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
dev->EP_in[ep].Num = ep + 1;
dev->EP_out[ep].Num = ep + 1;
dev->EP_in[ep].pid = USB_TOKEN_IN;
dev->EP_out[ep].pid = USB_TOKEN_OUT;
dev->EP_in[ep].Type = USB_ENDPOINT_XFER_INVALID;
dev->EP_out[ep].Type = USB_ENDPOINT_XFER_INVALID;
dev->EP_in[ep].IfNum = USB_INTERFACE_INVALID;
dev->EP_out[ep].IfNum = USB_INTERFACE_INVALID;
dev->EP_in[ep].MaxPacketSize = 0;
dev->EP_out[ep].MaxPacketSize = 0;
dev->EP_in[ep].Dev = dev;
dev->EP_out[ep].Dev = dev;
dev->EP_in[ep].Pipeline = false;
dev->EP_out[ep].Pipeline = false;
}
}
/*
* From XQEMU:
* This function creates a serial number for a usb device.
* The serial number should:
* (a) Be unique within the emulator.
* (b) Be constant, so you don't get a new one each
* time the guest is started.
* So we are using the physical location to generate a serial number
* from it. It has three pieces: First a fixed, device-specific
* prefix. Second the device path of the host controller (which is
* the pci address in most cases). Third the physical port path.
* Results in serial numbers like this: "314159-0000:00:1d.7-3".
*/
void USBPCIDevice::USB_CreateSerial(XboxDeviceState* dev, const char* str) {
const USBDesc* desc = USBDesc_GetUsbDeviceDesc(dev);
int index = desc->id.iSerialNumber;
USBDescString* s;
char serial[64];
char* path;
int dst;
assert(index != 0 && str != nullptr);
dst = std::snprintf(serial, sizeof(serial), "%s", str);
dst += std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", m_PciPath);
std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", dev->Port->Path);
USBDesc_SetString(dev, index, serial);
}
const USBDesc* USBPCIDevice::USBDesc_GetUsbDeviceDesc(XboxDeviceState* dev) {
USBDeviceClass* klass = dev->klass;
if (dev->UsbDesc) {
return dev->UsbDesc;
}
return klass->usb_desc;
}
void USBPCIDevice::USBDesc_Init(XboxDeviceState* dev) {
const USBDesc* desc = USBDesc_GetUsbDeviceDesc(dev);
assert(desc != NULL);
dev->Speed = USB_SPEED_FULL;
dev->SpeedMask = 0;
if (desc->full) {
dev->SpeedMask |= USB_SPEED_MASK_FULL;
}
USBDesc_SetDefaults(dev);
}
void USBPCIDevice::USBDesc_SetDefaults(XboxDeviceState* dev) {
const USBDesc *desc = USBDesc_GetUsbDeviceDesc(dev);
assert(desc != NULL);
switch (dev->Speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
{
dev->Device = desc->full;
break;
}
default:
log_warning("Unknown speed parameter %d set in %s", dev->ProductDesc.c_str());
}
USBDesc_SetConfig(dev, 0);
}
int USBPCIDevice::USBDesc_SetConfig(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
USBDesc_SetInterface(dev, i, 0);
}
for (; i < USB_MAX_INTERFACES; i++) { // null the remaining interfaces
dev->AltSetting[i] = 0;
dev->Ifaces[i] = nullptr;
}
return 0;
}
int USBPCIDevice::USBDesc_SetInterface(XboxDeviceState* dev, int index, int value) {
const USBDescIface* iface;
int old;
iface = USBDesc_FindInterface(dev, index, value);
if (iface == nullptr) {
return -1;
}
old = dev->AltSetting[index];
dev->AltSetting[index] = value;
dev->Ifaces[index] = iface;
USBDesc_EpInit(dev);
if (old != value) {
USB_DeviceSetInterface(dev, index, old, value);
}
return 0;
}
const USBDescIface* USBPCIDevice::USBDesc_FindInterface(XboxDeviceState* dev, int nif, int alt) {
const USBDescIface* iface;
int i;
if (!dev->Config) { // no configuration descriptor here, nothing to search
return nullptr;
}
for (i = 0; i < dev->Config->nif; i++) { // find the desired interface
iface = &dev->Config->ifs[i];
if (iface->bInterfaceNumber == nif &&
iface->bAlternateSetting == alt) {
return iface;
}
}
return nullptr; // not found
}
void USBPCIDevice::USBDesc_EpInit(XboxDeviceState* dev) {
const USBDescIface *iface;
int i, e, pid, ep;
USB_EpInit(dev); // reset endpoints (because we changed descriptors in use?)
for (i = 0; i < dev->NumInterfaces; i++) {
iface = dev->Ifaces[i];
if (iface == nullptr) {
continue;
}
for (e = 0; e < iface->bNumEndpoints; e++) {
// From the standard:
// "bEndpointAddress:
// Bit 3...0: The endpoint number
// Bit 6...4: Reserved, reset to zero
// Bit 7: Direction -> 0 = OUT endpoint, 1 = IN endpoint
// bmAttributes:
// Bit 1..0: Transfer Type
// 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt. All other bits are reserved"
pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = iface->eps[e].bEndpointAddress & 0xF;
USB_EPsetType(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
USB_EPsetIfnum(dev, pid, ep, iface->bInterfaceNumber);
USB_EPsetMaxPacketSize(dev, pid, ep, iface->eps[e].wMaxPacketSize);
}
}
}
int USBPCIDevice::USBDesc_HandleControl(XboxDeviceState* dev, USBPacket *p, int request, int value, int index, int length, uint8_t* data) {
const USBDesc* desc = USBDesc_GetUsbDeviceDesc(dev);
int ret = -1;
assert(desc != nullptr);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
{
// From the standard: "This request sets the device address for all future device accesses.
// The wValue field specifies the device address to use for all subsequent accesses"
dev->Addr = value;
log_debug("Address 0x%X set for device %s", dev->Addr, dev->ProductDesc.c_str());
ret = 0;
break;
}
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
{
// From the standard: "This request returns the specified descriptor if the descriptor exists.
// The wValue field specifies the descriptor type in the high byte and the descriptor index in the low byte.
// The wIndex field specifies the Language ID for string descriptors or is reset to zero for other descriptors"
ret = USBDesc_HandleStandardGetDescriptor(dev, p, value, data, length);
break;
}
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
{
// From the standard: "This request returns the current device configuration value.
// If the returned value is zero, the device is not configured"
data[0] = dev->Config ? dev->Config->bConfigurationValue : 0;
p->ActualLength = 1;
ret = 0;
break;
}
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
{
// From the standard: "This request sets the device configuration. The lower byte of the wValue field specifies the desired configuration.
// This configuration value must be zero or match a configuration value from a configuration descriptor"
ret = USBDesc_SetConfig(dev, value);
log_debug("Received standard SetConfiguration() request for device at address 0x%X. Configuration selected is %d and returned %d",
dev->Addr, value, ret);
break;
}
case DeviceRequest | USB_REQ_GET_STATUS:
{
// From the standard: "This request returns the status for the specified recipient. The Recipient bits of the bmRequestType field
// specify the desired recipient. The data returned is the current status of the specified recipient."
// From XQEMU:
/* Default state: Device behavior when this request is received while
* the device is in the Default state is not specified.
* We return the same value that a configured device would return if
* it used the first configuration. */
const USBDescConfig* config = dev->Config ? dev->Config : &dev->Device->confs[0];
data[0] = 0;
if (config->bmAttributes & 0x40) {
data[0] |= 1 << USB_DEVICE_SELF_POWERED;
}
if (dev->RemoteWakeup) {
data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
}
data[1] = 0x00;
p->ActualLength = 2;
ret = 0;
break;
}
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
{
// From the standard: "This request is used to clear or disable a specific feature.
// Feature selector values in wValue must be appropriate to the recipient"
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->RemoteWakeup = 0;
ret = 0;
}
log_debug("Received standard ClearFeature() request for device at address 0x%X. Feature selected is %d and returned %d",
dev->Addr, value, ret);
break;
}
case DeviceOutRequest | USB_REQ_SET_FEATURE:
{
// From the standard: "This request is used to set or enable a specific feature.
// Feature selector values in wValue must be appropriate to the recipient"
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->RemoteWakeup = 1;
ret = 0;
}
log_debug("Received standard SetFeature() request for device at address 0x%X. Feature selected is %d and returned %d",
dev->Addr, value, ret);
break;
}
case InterfaceRequest | USB_REQ_GET_INTERFACE:
{
// From the standard: "This request returns the selected alternate setting for the specified interface.
// wValue = Zero; wIndex = Interface"
if (index < 0 || index >= dev->NumInterfaces) {
break;
}
data[0] = dev->AltSetting[index];
p->ActualLength = 1;
ret = 0;
break;
}
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
{
// From the standard: "This request allows the host to select an alternate setting for the specified interface"
// wValue = Alternative Setting; wIndex = Interface
ret = USBDesc_SetInterface(dev, index, value);
log_debug("Received standard SetInterface() request for device at address 0x%X. Interface selected is %d, Alternative Setting is %d and returned %d", dev->Addr, index, value, ret);
break;
}
default:
}
return ret;
}
int USBPCIDevice::USBDesc_HandleStandardGetDescriptor(XboxDeviceState* dev, USBPacket* p,
int value, uint8_t* dest, size_t len) {
const USBDesc* desc = USBDesc_GetUsbDeviceDesc(dev);
uint8_t buf[256];
uint8_t type = value >> 8; // recover descriptor type from wValue
uint8_t index = value & 0xFF; // recover descriptor index from wValue
int ret = -1;
int flags = 0;
// Dropped from XQEMU bcdUSB check for usb 3.0 devices
// From the standard: "The standard request to a device supports three types of descriptors: DEVICE, CONFIGURATION, and STRING."
switch (type) {
case USB_DT_DEVICE:
{
ret = USB_ReadDeviceDesc(&desc->id, dev->Device, buf, sizeof(buf));
log_debug("Read operation of device descriptor of device 0x%X returns %d", dev->Addr, ret);
break;
}
case USB_DT_CONFIG:
{
if (index < dev->Device->bNumConfigurations) {
ret = USB_ReadConfigurationDesc(dev->Device->confs + index, flags, buf, sizeof(buf));
}
log_debug("Read operation of configuration descriptor %d of device 0x%X returns %d", index, dev->Addr, ret);
break;
}
case USB_DT_STRING:
{
ret = USB_ReadStringDesc(dev, index, buf, sizeof(buf));
log_debug("Read operation of string descriptor %d of device 0x%X returns %d", index, dev->Addr, ret);
break;
}
// Dropped from XQEMU descriptor types USB_DT_DEVICE_QUALIFIER (6), USB_DT_OTHER_SPEED_CONFIG (7) -> usb 2.0 only and reserved on usb 3.0,
// USB_DT_BOS (15) and USB_DT_DEBUG (10) -> usb 3.0 only
default:
log_warning("%s: device address %d unknown type %d (len %zd)", __func__, dev->Addr, type, len);
break;
}
if (ret > 0) {
if (ret > len) {
ret = len;
}
std::memcpy(dest, buf, ret);
p->ActualLength = ret;
ret = 0;
}
return ret;
}
int USBPCIDevice::USB_ReadDeviceDesc(const USBDescID* id, const USBDescDevice* dev, uint8_t* dest, size_t len) {
uint8_t bLength = 0x12; // a device descriptor is 18 bytes large
USBDescriptor* d = reinterpret_cast<USBDescriptor*>(dest);
if (len < bLength) {
return -1;
}
d->bLength = bLength;
d->bDescriptorType = USB_DT_DEVICE;
d->u.device.bcdUSB_lo = GET_WORD_LOW(dev->bcdUSB);
d->u.device.bcdUSB_hi = GET_WORD_HIGH(dev->bcdUSB);
d->u.device.bDeviceClass = dev->bDeviceClass;
d->u.device.bDeviceSubClass = dev->bDeviceSubClass;
d->u.device.bDeviceProtocol = dev->bDeviceProtocol;
d->u.device.bMaxPacketSize0 = dev->bMaxPacketSize0;
d->u.device.idVendor_lo = GET_WORD_LOW(id->idVendor);
d->u.device.idVendor_hi = GET_WORD_HIGH(id->idVendor);
d->u.device.idProduct_lo = GET_WORD_LOW(id->idProduct);
d->u.device.idProduct_hi = GET_WORD_HIGH(id->idProduct);
d->u.device.bcdDevice_lo = GET_WORD_LOW(id->bcdDevice);
d->u.device.bcdDevice_hi = GET_WORD_HIGH(id->bcdDevice);
d->u.device.iManufacturer = id->iManufacturer;
d->u.device.iProduct = id->iProduct;
d->u.device.iSerialNumber = id->iSerialNumber;
d->u.device.bNumConfigurations = dev->bNumConfigurations;
return bLength;
}
int USBPCIDevice::USB_ReadConfigurationDesc(const USBDescConfig* conf, int flags, uint8_t* dest, size_t len) {
uint8_t bLength = 0x09; // a configuration descriptor is 9 bytes large
uint16_t wTotalLength = 0;
USBDescriptor* d = reinterpret_cast<USBDescriptor*>(dest);
int i, rc;
if (len < bLength) {
return -1;
}
// From the standard: "A request for a configuration descriptor returns the configuration descriptor, all interface
// descriptors, and endpoint descriptors for all of the interfaces in a single request."
d->bLength = bLength;
d->bDescriptorType = USB_DT_CONFIG;
d->u.config.bNumInterfaces = conf->bNumInterfaces;
d->u.config.bConfigurationValue = conf->bConfigurationValue;
d->u.config.iConfiguration = conf->iConfiguration;
d->u.config.bmAttributes = conf->bmAttributes;
d->u.config.bMaxPower = conf->bMaxPower;
wTotalLength += bLength;
for (i = 0; i < conf->nif; i++) {
rc = USB_ReadInterfaceDesc(conf->ifs + i, flags, dest + wTotalLength, len - wTotalLength);
if (rc < 0) {
return rc;
}
wTotalLength += rc;
}
d->u.config.wTotalLength_lo = GET_WORD_LOW(wTotalLength);
d->u.config.wTotalLength_hi = GET_WORD_HIGH(wTotalLength);
return wTotalLength;
}
int USBPCIDevice::USB_ReadInterfaceDesc(const USBDescIface* iface, int flags, uint8_t* dest, size_t len) {
uint8_t bLength = 0x09; // a interface descriptor is 9 bytes large
int i, rc, pos = 0;
USBDescriptor* d = reinterpret_cast<USBDescriptor*>(dest);
if (len < bLength) {
return -1;
}
// From the standard: "The first interface descriptor follows the configuration descriptor.
// The endpoint descriptors for the first interface follow the first interface descriptor.
// If there are additional interfaces, their interface descriptor and endpoint descriptors
// follow the first interface's endpoint descriptors. Class-specific and/or vendor-specific
// descriptors follow the standard descriptors they extend or modify."
d->bLength = bLength;
d->bDescriptorType = USB_DT_INTERFACE;
d->u.iface.bInterfaceNumber = iface->bInterfaceNumber;
d->u.iface.bAlternateSetting = iface->bAlternateSetting;
d->u.iface.bNumEndpoints = iface->bNumEndpoints;
d->u.iface.bInterfaceClass = iface->bInterfaceClass;
d->u.iface.bInterfaceSubClass = iface->bInterfaceSubClass;
d->u.iface.bInterfaceProtocol = iface->bInterfaceProtocol;
d->u.iface.iInterface = iface->iInterface;
pos += bLength;
for (i = 0; i < iface->ndesc; i++) {
rc = USB_ReadOtherDesc(iface->descs + i, dest + pos, len - pos);
if (rc < 0) {
return rc;
}
pos += rc;
}
for (i = 0; i < iface->bNumEndpoints; i++) {
rc = USB_ReadEndpointDesc(iface->eps + i, flags, dest + pos, len - pos);
if (rc < 0) {
return rc;
}
pos += rc;
}
return pos;
}
int USBPCIDevice::USB_ReadOtherDesc(const USBDescOther* desc, uint8_t* dest, size_t len) {
int bLength = desc->length ? desc->length : desc->data[0];
if (len < bLength) {
return -1;
}
std::memcpy(dest, desc->data, bLength);
return bLength;
}
int USBPCIDevice::USB_ReadEndpointDesc(const USBDescEndpoint* ep, int flags, uint8_t* dest, size_t len) {
uint8_t bLength = ep->is_audio ? 0x09 : 0x07; // an endpoint descriptor is 7 bytes large (or 9 if it is an audio device)
uint8_t extralen = ep->extra ? ep->extra[0] : 0;
USBDescriptor* d = reinterpret_cast<USBDescriptor*>(dest);
if (len < bLength + extralen) {
return -1;
}
d->bLength = bLength;
d->bDescriptorType = USB_DT_ENDPOINT;
d->u.endpoint.bEndpointAddress = ep->bEndpointAddress;
d->u.endpoint.bmAttributes = ep->bmAttributes;
d->u.endpoint.wMaxPacketSize_lo = GET_WORD_LOW(ep->wMaxPacketSize);
d->u.endpoint.wMaxPacketSize_hi = GET_WORD_HIGH(ep->wMaxPacketSize);
d->u.endpoint.bInterval = ep->bInterval;
if (ep->is_audio) {
d->u.endpoint.bRefresh = ep->bRefresh;
d->u.endpoint.bSynchAddress = ep->bSynchAddress;
}
// Dropped from XQEMU the reading of SuperSpeed Endpoint Companion descriptors since those are usb 3.0 specific
if (ep->extra) {
std::memcpy(dest + bLength, ep->extra, extralen);
}
return bLength + extralen;
}
int USBPCIDevice::USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* dest, size_t len) {
uint8_t bLength, pos, i;
const char* str;
if (len < 4) {
return -1;
}
// From the standard: "String index zero for all languages returns a string descriptor
// that contains an array of two-byte LANGID codes supported by the device."
if (index == 0) {
/* language ids */
dest[0] = 4;
dest[1] = USB_DT_STRING;
dest[2] = 0x09;
dest[3] = 0x04; // we only support English (United States)
return 4;
}
str = USBDesc_GetString(dev, index);
if (str == nullptr) {
return 0;
}
// From the standard: "The UNICODE string descriptor is not NULL-terminated. The string length is
// computed by subtracting two from the value of the first byte of the descriptor"
bLength = strlen(str) * 2 + 2;
dest[0] = bLength;
dest[1] = USB_DT_STRING;
i = 0; pos = 2;
while (pos + 1 < bLength && pos + 1 < len) {
dest[pos++] = str[i++];
dest[pos++] = 0;
}
return pos;
}
void USBPCIDevice::USBDesc_SetString(XboxDeviceState* dev, int index, const char* str) {
USBDescString* s;
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 = str;
}
const char* USBPCIDevice::USBDesc_GetString(XboxDeviceState* dev, int index) {
USBDescString* s;
QLIST_FOREACH(s, &dev->Strings, next) {
if (s->index == index) {
return s->str.c_str();
}
}
return nullptr;
}
}

View file

@ -94,19 +94,18 @@ public:
void USB_Detach(USBPort* Port);
// a device downstream from the device attached to the port (attached through a hub) is detached
void ChildDetach(USBPort* Port, XboxDeviceState* Child);
// TODO
void Wakeup(USBPort* Port);
// update port status when a device is detached
void USB_Wakeup(USBEndpoint* ep);
// TODO
void Complete(USBPort* Port, USBPacket *P);
// reset a device
void USB_DeviceReset(XboxDeviceState* Dev);
//
XboxDeviceState* USB_DeviceFindDevice(XboxDeviceState* Dev, uint8_t Addr);
// find the device connected to the supplied port and address
XboxDeviceState* USB_FindDevice(USBPort* Port, uint8_t Addr);
// find the requested endpoint in the supplied device
USBEndpoint* USB_GetEP(XboxDeviceState* Dev, int Pid, int Ep);
// setup a packet for transfer
void USB_PacketSetup(USBPacket* p, int Pid, USBEndpoint* Ep, unsigned int Stream,
uint64_t Id, bool ShortNotOK, bool IntReq);
void USB_PacketSetup(USBPacket* p, int Pid, USBEndpoint* Ep, unsigned int Stream, uint64_t Id, bool ShortNotOK, bool IntReq);
// check if the state of the packet is queued or async
bool USB_IsPacketInflight(USBPacket* p);
// append the user buffer to the packet
@ -135,7 +134,7 @@ public:
// call usb class init function
int USB_DeviceInit(XboxDeviceState* dev);
// call usb class find_device function
XboxDeviceState * USB_FindDevice(USBPort* Port, uint8_t Addr);
XboxDeviceState* USB_DeviceFindDevice(XboxDeviceState* Dev, uint8_t Addr);
// call usb class cancel_packet function
void USB_DeviceCancelPacket(XboxDeviceState* dev, USBPacket* p);
// call usb class handle_destroy function
@ -162,6 +161,46 @@ public:
void USB_EPsetMaxPacketSize(XboxDeviceState* dev, int pid, int ep, uint16_t raw);
// assign port numbers (also for hubs)
void USB_PortLocation(USBPort* downstream, USBPort* upstream, int portnr);
// initialize the endpoints of this peripheral
void USB_EpInit(XboxDeviceState* dev);
// reset all endpoints of this peripheral
void USB_EpReset(XboxDeviceState* dev);
// create a serial number for the device
void USB_CreateSerial(XboxDeviceState* dev, const char* str);
// start descriptors initialization
void USBDesc_Init(XboxDeviceState* dev);
// get device descriptor
const USBDesc* USBDesc_GetUsbDeviceDesc(XboxDeviceState* dev);
// set the descriptors to use for this device
void USBDesc_SetDefaults(XboxDeviceState* dev);
// set the configuration to use
int USBDesc_SetConfig(XboxDeviceState* dev, int value);
// set the interface to use
int USBDesc_SetInterface(XboxDeviceState* dev, int index, int value);
// find the interface to use
const USBDescIface* USBDesc_FindInterface(XboxDeviceState* dev, int nif, int alt);
// setup endpoints and their descriptors
void USBDesc_EpInit(XboxDeviceState* dev);
// handle standard control request
int USBDesc_HandleControl(XboxDeviceState *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data);
// handle standard GetDescriptor() request
int USBDesc_HandleStandardGetDescriptor(XboxDeviceState* dev, USBPacket* p, int value, uint8_t* dest, size_t len);
// return the binary rapresentation of a device descriptor
int USB_ReadDeviceDesc(const USBDescID* id, const USBDescDevice* dev, uint8_t* dest, size_t len);
// return the binary rapresentation of configuration descriptors
int USB_ReadConfigurationDesc(const USBDescConfig* conf, int flags, uint8_t* dest, size_t len);
// return the binary rapresentation of interface descriptors
int USB_ReadInterfaceDesc(const USBDescIface* iface, int flags, uint8_t* dest, size_t len);
// return the binary rapresentation of class-specific descriptors
int USB_ReadOtherDesc(const USBDescOther* desc, uint8_t* dest, size_t len);
// return the binary rapresentation of endpoint descriptors
int USB_ReadEndpointDesc(const USBDescEndpoint* ep, int flags, uint8_t* dest, size_t len);
// return the binary rapresentation of string descriptors
int USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* dest, size_t len);
// set a string in the string descriptor with the supplied index
void USBDesc_SetString(XboxDeviceState* dev, int index, const char* str);
// get a string in the string descriptor with the supplied index
const char* USBDesc_GetString(XboxDeviceState* dev, int index);
private:
uint8_t m_irqn;
Cpu* m_cpu;