Implemented some hub commands + major refactoring

This commit is contained in:
ergo720 2018-07-03 23:11:41 +02:00
parent 4e3d0b307a
commit 36038db4fa
7 changed files with 612 additions and 296 deletions

View File

@ -159,18 +159,18 @@ static const USBDesc desc_hub(true);
int Hub::Init(int pport)
{
ClassInitFn();
UsbEpInit();
int rc = UsbClaimPort(pport);
XboxDeviceState* dev = ClassInitFn();
m_UsbDev->UsbEpInit(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;
}
@ -181,91 +181,57 @@ 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;
m_pDeviceStruct->ProductDesc = "Cxbx-Reloaded USB Hub";
QLIST_INIT(&m_pDeviceStruct->Strings);
m_pDeviceStruct->klass = m_pPeripheralFuncStruct;
XboxDeviceState* dev = &m_HubState->dev;
dev->ProductDesc = "Cxbx-Reloaded USB Hub";
QLIST_INIT(&dev->Strings);
dev->klass = m_pPeripheralFuncStruct;
{
using namespace std::placeholders;
m_pPeripheralFuncStruct->init = std::bind(&Hub::UsbHub_Initfn, this, _1);
m_pPeripheralFuncStruct->find_device = std::bind(&Hub::UsbHub_FindDevice, this, _1, _2);
m_pPeripheralFuncStruct->handle_reset = std::bind(&Hub::UsbHub_HandleReset, this);
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;
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;
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;
@ -286,8 +252,8 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev)
return -1;
}
CreateSerial(dev);
UsbDescInit(dev);
m_UsbDev->CreateSerial(dev);
m_UsbDev->UsbDescInit(dev);
m_HubState->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 1);
ops = new USBPortOps();
@ -296,7 +262,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);
}
@ -310,6 +276,24 @@ 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;
@ -328,185 +312,297 @@ void Hub::UsbHub_HandleReset()
}
}
/*
* 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) {
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->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)
void Hub::UsbHub_HandleControl(XboxDeviceState* dev, USBPacket* p,
int request, int value, int index, int length, uint8_t* data)
{
const USBDesc *desc = GetUsbDeviceDesc(dev);
USBHubState *s = (USBHubState *)dev;
int ret;
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0) {
return;
}
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;
}
}
break;
case ClearPortFeature:
{
unsigned int n = index - 1;
USBHubPort *port;
trace_usb_hub_clear_port_feature(s->dev.addr, index,
feature_name(value));
if (n >= NUM_PORTS) {
goto fail;
}
port = &s->ports[n];
switch (value) {
case PORT_ENABLE:
port->wPortStatus &= ~PORT_STAT_ENABLE;
break;
case PORT_C_ENABLE:
port->wPortChange &= ~PORT_STAT_C_ENABLE;
break;
case PORT_SUSPEND:
port->wPortStatus &= ~PORT_STAT_SUSPEND;
break;
case PORT_C_SUSPEND:
port->wPortChange &= ~PORT_STAT_C_SUSPEND;
break;
case PORT_C_CONNECTION:
port->wPortChange &= ~PORT_STAT_C_CONNECTION;
break;
case PORT_C_OVERCURRENT:
port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
break;
case PORT_C_RESET:
port->wPortChange &= ~PORT_STAT_C_RESET;
break;
default:
goto fail;
}
}
break;
case GetHubDescriptor:
{
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:
fail:
p->status = USB_RET_STALL;
break;
}
}
void Hub::UsbHub_Attach(USBPort* port1)
{
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
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 {
port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
}
m_UsbDev->USB_Wakeup(m_HubState->intr);
}
void Hub::UsbHub_Detach(USBPort* port1)
{
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
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;
}
m_UsbDev->USB_Wakeup(m_HubState->intr);
}
void Hub::UsbHub_ChildDetach(XboxDeviceState* child)
{
// Pass along to upstream
m_HubState->dev.Port->Operations->child_detach(child);
}
void Hub::UsbHub_Wakeup(USBPort* port1)
{
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
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);
}
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
const USBDesc *desc = usb_device_get_usb_desc(dev);
int ret = -1;
assert(desc != NULL);
switch (dev->Speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL: {
dev->Device = desc->full;
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
dev->addr = value;
trace_usb_set_addr(dev->addr);
ret = 0;
break;
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
ret = usb_desc_get_descriptor(dev, p, value, data, length);
break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
/*
* 9.4.2: 0 should be returned if the device is unconfigured, otherwise
* the non zero value of bConfigurationValue.
*/
data[0] = dev->config ? dev->config->bConfigurationValue : 0;
p->actual_length = 1;
ret = 0;
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
ret = usb_desc_set_config(dev, value);
trace_usb_set_config(dev->addr, value, ret);
break;
case DeviceRequest | USB_REQ_GET_STATUS: {
const USBDescConfig *config = dev->config ?
dev->config : &dev->device->confs[0];
data[0] = 0;
/*
* 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.
*/
if (config->bmAttributes & 0x40) {
data[0] |= 1 << USB_DEVICE_SELF_POWERED;
}
if (dev->remote_wakeup) {
data[0] |= 1 << USB_DEVICE_REMOTE_WAKEUP;
}
data[1] = 0x00;
p->actual_length = 2;
ret = 0;
break;
}
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->remote_wakeup = 0;
ret = 0;
}
trace_usb_clear_device_feature(dev->addr, value, ret);
break;
case DeviceOutRequest | USB_REQ_SET_FEATURE:
if (value == USB_DEVICE_REMOTE_WAKEUP) {
dev->remote_wakeup = 1;
ret = 0;
}
trace_usb_set_device_feature(dev->addr, value, ret);
break;
case InterfaceRequest | USB_REQ_GET_INTERFACE:
if (index < 0 || index >= dev->ninterfaces) {
break;
}
default:
EmuWarning("Unknown speed parameter %d set in %s", dev->ProductDesc.c_str());
}
UsbDescSetConfig(dev, 0);
}
data[0] = dev->altsetting[index];
p->actual_length = 1;
ret = 0;
break;
case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
ret = usb_desc_set_interface(dev, index, value);
trace_usb_set_interface(dev->addr, index, value, ret);
break;
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 == nullptr) {
return -1;
}
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;
}
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::UsbDescEpInit(XboxDeviceState* dev)
{
const USBDescIface *iface;
int i, e, pid, ep;
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);
}
}
return ret;
}

View File

@ -49,23 +49,25 @@ typedef enum {
/* 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();
private:
// usb device this hub is attached to
USBDevice* m_UsbDev = nullptr;
USBDevice* m_UsbDev;
// hub state
USBHubState* m_HubState = nullptr;
USBHubState* m_HubState;
// hub class functions
USBDeviceClass* m_pPeripheralFuncStruct;
// 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);
@ -77,34 +79,13 @@ class Hub final : public UsbPeripheral
// 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

@ -197,7 +197,7 @@ OHCI::OHCI(int Irq, USBDevice* 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

@ -262,7 +262,7 @@ class OHCI
// 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

@ -104,16 +104,6 @@ void USBDevice::USB_PortReset(USBPort* Port)
USB_DeviceReset(dev);
}
void USBDevice::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 USBDevice::USB_Attach(USBPort* Port)
{
XboxDeviceState* dev = Port->Dev;
@ -126,6 +116,25 @@ void USBDevice::USB_Attach(USBPort* Port)
USB_DeviceHandleAttach(dev);
}
void USBDevice::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 USBDevice::USB_Wakeup(USBEndpoint* ep)
{
XboxDeviceState* dev = ep->Dev;
if (dev->RemoteWakeup && dev->Port && dev->Port->Operations->wakeup) {
dev->Port->Operations->wakeup(dev->Port);
}
}
void USBDevice::USB_DeviceReset(XboxDeviceState* dev)
{
if (dev == nullptr || !dev->Attached) {
@ -644,3 +653,222 @@ void USBDevice::USB_DeviceAttach(XboxDeviceState* dev)
dev->Attached++;
USB_Attach(port);
}
void USBDevice::UsbEpInit(XboxDeviceState* dev)
{
UsbEpReset(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 USBDevice::UsbEpReset(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 USBDevice::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_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* USBDevice::GetUsbDeviceDesc(XboxDeviceState* dev)
{
USBDeviceClass* klass = dev->klass;
if (dev->UsbDesc) {
return dev->UsbDesc;
}
return klass->usb_desc;
}
void USBDevice::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 USBDevice::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());
}
UsbDescSetConfig(dev, 0);
}
int USBDevice::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 USBDevice::UsbDescSetInterface(XboxDeviceState* dev, int index, int value)
{
const USBDescIface* iface;
int old;
iface = UsbDescFindInterface(dev, index, value);
if (iface == nullptr) {
return -1;
}
old = dev->AltSetting[index];
dev->AltSetting[index] = value;
dev->Ifaces[index] = iface;
UsbDescEpInit(dev);
if (old != value) {
USB_DeviceSetInterface(dev, index, old, value);
}
return 0;
}
const USBDescIface* USBDevice::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 USBDevice::UsbDescEpInit(XboxDeviceState* dev)
{
const USBDescIface *iface;
int i, e, pid, ep;
UsbEpInit(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);
}
}
}

View File

@ -80,14 +80,14 @@ class USBDevice : public PCIDevice {
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
@ -121,7 +121,7 @@ class USBDevice : public PCIDevice {
// 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
@ -148,6 +148,26 @@ class USBDevice : public PCIDevice {
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 UsbEpInit(XboxDeviceState* dev);
// reset all endpoints of this peripheral
void UsbEpReset(XboxDeviceState* dev);
// create a serial number for the device
void CreateSerial(XboxDeviceState* dev);
// start descriptors initialization
void UsbDescInit(XboxDeviceState* dev);
// get device descriptor
const USBDesc* GetUsbDeviceDesc(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);
};
#endif

View File

@ -113,6 +113,9 @@ struct USBDescEndpoint {
uint8_t is_audio; /* has bRefresh + bSynchAddress */
uint8_t* extra;
// 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 */
@ -201,7 +204,7 @@ 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
@ -262,7 +265,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
@ -278,7 +281,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 */
@ -329,16 +332,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;
};
#endif