small OHCI stuff + almost done with Hub initialization

This commit is contained in:
ergo720 2018-07-02 22:15:39 +02:00
parent 0691b8bfb4
commit 13b20e6741
7 changed files with 289 additions and 128 deletions

View File

@ -40,6 +40,20 @@
#define NUM_PORTS 8
#define PORT_STAT_CONNECTION 0x0001
#define PORT_STAT_ENABLE 0x0002
#define PORT_STAT_SUSPEND 0x0004
#define PORT_STAT_OVERCURRENT 0x0008
#define PORT_STAT_RESET 0x0010
#define PORT_STAT_POWER 0x0100
#define PORT_STAT_LOW_SPEED 0x0200
#define PORT_STAT_C_CONNECTION 0x0001
#define PORT_STAT_C_ENABLE 0x0002
#define PORT_STAT_C_SUSPEND 0x0004
#define PORT_STAT_C_OVERCURRENT 0x0008
#define PORT_STAT_C_RESET 0x0010
// To avoid including Xbox.h
extern USBDevice* g_USB0;
@ -57,13 +71,13 @@ int PlayerToUsbArray[] = {
struct USBHubPort {
USBPort port; // downstream port status
uint16_t wPortStatus;
uint16_t wPortChange;
uint16_t wPortStatus; // Port Status Field, in accordance with the standard
uint16_t wPortChange; // Port Change Field, in accordance with the standard
};
struct USBHubState {
XboxDeviceState dev; // hub device status
USBEndpoint* intr;
USBEndpoint* intr; // interrupt endpoint of the hub
USBHubPort ports[NUM_PORTS]; // downstream ports of the hub
};
@ -153,15 +167,13 @@ int Hub::Init(int pport)
}
rc = m_UsbDev->USB_DeviceInit(m_pDeviceStruct);
if (rc != 0) {
usb_release_port(dev);
UsbReleasePort(m_pDeviceStruct);
return rc;
}
if (dev->auto_attach) {
rc = usb_device_attach(dev);
if (rc != 0) {
usb_qdev_exit(qdev);
return rc;
}
rc = usb_device_attach(dev);
if (rc != 0) {
usb_qdev_exit(qdev);
return rc;
}
}
@ -240,7 +252,6 @@ void Hub::UsbEpReset()
int Hub::UsbClaimPort(int pport)
{
USBPort* port;
int usb_port;
assert(m_pDeviceStruct->Port == nullptr);
@ -260,10 +271,20 @@ int Hub::UsbClaimPort(int pport)
return 0;
}
void Hub::UsbReleasePort(XboxDeviceState* dev)
{
USBPort* port = dev->Port;
assert(port != nullptr);
port->Dev = nullptr;
dev->Port = nullptr;
}
int Hub::UsbHub_Initfn(XboxDeviceState* dev)
{
USBHubState* s = container_of(dev, USBHubState, dev);
USBHubPort *port;
USBHubPort* port;
int i;
if (dev->Port->HubCount == 5) {
@ -273,18 +294,35 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev)
CreateSerial(dev);
UsbDescInit(dev);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
s->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 1);
for (i = 0; i < NUM_PORTS; i++) {
port = &s->ports[i];
usb_register_port(usb_bus_from_device(dev),
&port->port, s, i, &usb_hub_port_ops,
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
usb_port_location(&port->port, dev->port, i + 1);
m_UsbDev->USB_RegisterPort(&port->port, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
m_UsbDev->USB_PortLocation(&port->port, dev->Port, i + 1);
}
usb_hub_handle_reset(dev);
UsbHub_HandleReset(dev);
return 0;
}
void Hub::UsbHub_HandleReset(XboxDeviceState* dev)
{
USBHubState* s = container_of(dev, USBHubState, dev);
USBHubPort* port;
for (int i = 0; i < NUM_PORTS; i++) {
port = s->ports + i;
port->wPortStatus = PORT_STAT_POWER;
port->wPortChange = 0;
if (port->port.Dev && port->port.Dev->Attached) {
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;
}
}
}
}
/*
* From XQEMU:
* This function creates a serial number for a usb device.
@ -406,17 +444,17 @@ int Hub::UsbDescSetInterface(XboxDeviceState* dev, int index, int value)
int old;
iface = UsbDescFindInterface(dev, index, value);
if (iface == NULL) {
if (iface == nullptr) {
return -1;
}
old = dev->altsetting[index];
dev->altsetting[index] = value;
dev->ifaces[index] = iface;
usb_desc_ep_init(dev);
old = dev->AltSetting[index];
dev->AltSetting[index] = value;
dev->Ifaces[index] = iface;
UsbDescEpInit(dev);
if (old != value) {
usb_device_set_interface(dev, index, old, value);
m_UsbDev->USB_DeviceSetInterface(dev, index, old, value);
}
return 0;
}
@ -424,26 +462,46 @@ int Hub::UsbDescSetInterface(XboxDeviceState* dev, int index, int value)
const USBDescIface* Hub::UsbDescFindInterface(XboxDeviceState* dev, int nif, int alt)
{
const USBDescIface* iface;
int g, i;
int 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];
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 NULL;
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);
}
}
}

View File

@ -77,26 +77,30 @@ class Hub final : public UsbPeripheral
// TODO: perhaps these can be put in UsbPeripheral or USBDevice...
// initialize the endpoints of this peripheral
void UsbEpInit();
// destroy hub
// destroy hub resources
void HubCleanUp();
// reset all endpoints of this peripheral
void UsbEpReset();
// attach this hub to a usb port
// 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);
};
extern Hub* g_HubObjArray[4];

View File

@ -187,16 +187,27 @@
OHCI::OHCI(int Irq, USBDevice* UsbObj)
{
int offset = 0;
USBPortOps* ops;
m_IrqNum = Irq;
m_UsbDevice = UsbObj;
ops = new USBPortOps();
{
using namespace std::placeholders;
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, _1);
ops->wakeup = std::bind(&OHCI::OHCI_Wakeup, this, _1);
ops->complete = std::bind(&OHCI::OHCI_AsyncCompletePacket, this, _1, _2);
}
if (m_IrqNum == 9) {
offset = 2;
}
for (int i = 0; i < 2; i++) {
m_UsbDevice->USB_RegisterPort(&m_Registers.RhPort[i].UsbPort, i + offset, 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, ops);
}
OHCI_PacketInit(&m_UsbPacket);
@ -1437,6 +1448,43 @@ void OHCI::OHCI_Attach(USBPort* Port)
}
}
void OHCI::OHCI_ChildDetach(XboxDeviceState* child)
{
OHCI_AsyncCancelDevice(child);
}
void OHCI::OHCI_Wakeup(USBPort* port1)
{
OHCIPort* port = &m_Registers.RhPort[port1->PortIndex];
uint32_t intr = 0;
if (port->HcRhPortStatus & OHCI_PORT_PSS) {
DbgPrintf("Ohci: port %d: wakeup\n", port1->PortIndex);
port->HcRhPortStatus |= OHCI_PORT_PSSC;
port->HcRhPortStatus &= ~OHCI_PORT_PSS;
intr = OHCI_INTR_RHSC;
}
// Note that the controller can be suspended even if this port is not
if ((m_Registers.HcControl & OHCI_CTL_HCFS) == Suspend) {
DbgPrintf("Ohci: remote-wakeup: SUSPEND->RESUME\n");
// From the standard: "The only interrupts possible in the USBSUSPEND state are ResumeDetected (the
// Host Controller will have changed the HostControllerFunctionalState to the USBRESUME state)
// and OwnershipChange."
m_Registers.HcControl &= ~OHCI_CTL_HCFS;
m_Registers.HcControl |= Resume;
intr = OHCI_INTR_RD;
}
OHCI_SetInterrupt(intr);
}
void OHCI::OHCI_AsyncCompletePacket(USBPort* port, USBPacket* packet)
{
#ifdef DEBUG_PACKET
DPRINTF("Async packet complete\n");
#endif
m_AsyncComplete = 1;
OHCI_ProcessLists(1);
}
void OHCI::OHCI_AsyncCancelDevice(XboxDeviceState* dev)
{
if (m_AsyncTD &&

View File

@ -158,10 +158,6 @@ class OHCI
uint32_t OHCI_ReadRegister(xbaddr Addr);
// write a register
void OHCI_WriteRegister(xbaddr Addr, uint32_t Value);
// update ohci registers during a device attach
void OHCI_Attach(USBPort* Port);
// update ohci registers during a device detach
void OHCI_Detach(USBPort* Port);
// update the USBPort struct with the device attached
void OHCI_AssignUsbPortStruct(int port, XboxDeviceState* dev);
@ -263,6 +259,12 @@ class OHCI
void OHCI_AsyncCancelDevice(XboxDeviceState* dev);
// Process Control and Bulk lists
void OHCI_ProcessLists(int completion);
// see USBPortOps struct for info
void OHCI_Attach(USBPort* Port);
void OHCI_Detach(USBPort* Port);
void OHCI_ChildDetach(XboxDeviceState* child);
void OHCI_Wakeup(USBPort* port1);
void OHCI_AsyncCompletePacket(USBPort* port, USBPacket* packet);
};
#endif

View File

@ -86,13 +86,12 @@ void USBDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned
m_HostController->OHCI_WriteRegister(addr, value);
}
void USBDevice::USB_RegisterPort(USBPort* Port, int Index, int SpeedMask)
void USBDevice::USB_RegisterPort(USBPort* Port, int Index, int SpeedMask, USBPortOps* Ops)
{
Port->PortIndex = Index;
Port->SpeedMask = SpeedMask;
Port->HubCount = 0;
Port->Dev = nullptr;
std::snprintf(Port->Path, sizeof(Port->Path), "%d", Index + 1);
Port->Operations = Ops;
USB_PortLocation(Port, nullptr, Index + 1);
}
void USBDevice::USB_PortReset(USBPort* Port)
@ -164,8 +163,8 @@ USBEndpoint* USBDevice::USB_GetEP(XboxDeviceState* Dev, int Pid, int Ep)
if (Ep == 0) {
return &Dev->EP_ctl; // EndpointNumber zero represents the default control endpoint
}
assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
assert(Pid == USB_TOKEN_IN || Pid == USB_TOKEN_OUT);
assert(Ep > 0 && Ep <= USB_MAX_ENDPOINTS);
return eps + Ep - 1;
}
@ -509,51 +508,59 @@ int USBDevice::USB_DeviceInit(XboxDeviceState* dev)
void USBDevice::USB_DeviceHandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
USBDeviceClass* klass = dev->klass;
if (klass->handle_control) {
klass->handle_control(dev, p, request, value, index, length, data); // TODO: usb_hub_handle_control
klass->handle_control(dev, p, request, value, index, length, data);
}
}
void USBDevice::USB_DeviceHandleData(XboxDeviceState* dev, USBPacket* p)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
USBDeviceClass* klass = dev->klass;
if (klass->handle_data) {
klass->handle_data(dev, p); // TODO: usb_hub_handle_data
klass->handle_data(dev, p);
}
}
void USBDevice::USB_DeviceFlushEPqueue(XboxDeviceState* dev, USBEndpoint* ep)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
USBDeviceClass *klass = dev->klass;
if (klass->flush_ep_queue) {
klass->flush_ep_queue(dev, ep); // TODO: it's nullptr in XQEMU...
klass->flush_ep_queue(dev, ep);
}
}
void USBDevice::USB_DeviceCancelPacket(XboxDeviceState* dev, USBPacket* p)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
USBDeviceClass* klass = dev->klass;
if (klass->cancel_packet) {
klass->cancel_packet(dev, p); // TODO: it's nullptr in XQEMU...
klass->cancel_packet(dev, p);
}
}
XboxDeviceState* USBDevice::USB_DeviceFindDevice(XboxDeviceState* Dev, uint8_t Addr)
XboxDeviceState* USBDevice::USB_DeviceFindDevice(XboxDeviceState* dev, uint8_t Addr)
{
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(Dev);
USBDeviceClass* klass = dev->klass;
if (klass->find_device) {
return klass->find_device(Dev, Addr); // TODO: usb_hub_find_device
return klass->find_device(dev, Addr);
}
return nullptr;
}
void USBDevice::USB_DeviceEPstopped(XboxDeviceState* Dev, USBEndpoint* EP)
void USBDevice::USB_DeviceEPstopped(XboxDeviceState* dev, USBEndpoint* EP)
{
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(Dev);
USBDeviceClass* klass = dev->klass;
if (klass->ep_stopped) {
klass->ep_stopped(Dev, EP);
klass->ep_stopped(dev, EP);
}
}
void USBDevice::USB_DeviceSetInterface(XboxDeviceState* dev, int iface, int alt_old, int alt_new)
{
USBDeviceClass* klass = dev->klass;
if (klass->set_interface) {
klass->set_interface(dev, iface, alt_old, alt_new);
}
}
@ -567,3 +574,38 @@ void USBDevice::USB_CancelPacket(USBPacket* p)
USB_DeviceCancelPacket(p->Endpoint->Dev, p);
}
}
void USBDevice::USB_EPsetType(XboxDeviceState* dev, int pid, int ep, uint8_t type)
{
USBEndpoint* uep = USB_GetEP(dev, pid, ep);
uep->Type = type;
}
uint8_t USBDevice::USB_EPsetIfnum(XboxDeviceState* dev, int pid, int ep, uint8_t ifnum)
{
USBEndpoint* uep = USB_GetEP(dev, pid, ep);
uep->IfNum = ifnum;
}
void USBDevice::USB_EPsetMaxPacketSize(XboxDeviceState* dev, int pid, int ep, uint16_t raw)
{
USBEndpoint* uep = USB_GetEP(dev, pid, ep);
// Dropped from XQEMU the calculation max_packet_size = size * microframes since that's only true
// for high speed (usb 2.0) devices
uep->MaxPacketSize = raw & 0x7FF;
}
void USBDevice::USB_PortLocation(USBPort* downstream, USBPort* upstream, int portnr)
{
if (upstream) {
std::snprintf(downstream->Path, sizeof(downstream->Path), "%s.%d",
upstream->Path, portnr);
downstream->HubCount = upstream->HubCount + 1;
}
else {
std::snprintf(downstream->Path, sizeof(downstream->Path), "%d", portnr);
downstream->HubCount = 0;
}
}

View File

@ -41,9 +41,10 @@
#include "UsbCommon.h"
// Forward declare OHCI class for USBDevice class
// Forward declare OHCI class for m_HostController pointer
class OHCI;
/* Helper class which provides various functionality to both OHCI and usb device classes */
class USBDevice : public PCIDevice {
public:
// constructor
@ -68,12 +69,12 @@ class USBDevice : public PCIDevice {
const char* m_PciPath;
// register a port with the HC
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask);
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask, USBPortOps* Ops);
//
void USB_DeviceEPstopped(XboxDeviceState* Dev, USBEndpoint* Ep);
// reset a usb port
void USB_PortReset(USBPort* Port);
// a device is attched
// a device is attached
void USB_Attach(USBPort* Port);
// a device is detached
void USB_Detach(USBPort* Port);
@ -87,7 +88,7 @@ class USBDevice : public PCIDevice {
void USB_DeviceReset(XboxDeviceState* Dev);
// find the usb device with the supplied address
XboxDeviceState* USB_FindDevice(USBPort* Port, uint8_t Addr);
// ergo720: can probably be removed by calling directly usb_hub_find_device
//
XboxDeviceState* USB_DeviceFindDevice(XboxDeviceState* Dev, uint8_t Addr);
// find the requested endpoint in the supplied device
USBEndpoint* USB_GetEP(XboxDeviceState* Dev, int Pid, int Ep);
@ -114,21 +115,31 @@ class USBDevice : public PCIDevice {
void DoTokenOut(XboxDeviceState* s, USBPacket* p);
// copy the packet data to the buffer pointed to by ptr
void USB_PacketCopy(USBPacket* p, void* ptr, size_t bytes);
// Cancel an active packet. The packed must have been deferred by
// returning USB_RET_ASYNC from handle_packet, and not yet completed
void USB_CancelPacket(USBPacket* p);
// queue a packet to an endpoint
void USB_QueueOne(USBPacket* p);
// call usb class init function
int USB_DeviceInit(XboxDeviceState* dev);
//
// call usb class handle_control function
void USB_DeviceHandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data);
//
// call usb class handle_data function
void USB_DeviceHandleData(XboxDeviceState* dev, USBPacket* p);
//
// call usb class flush_ep_queue function
void USB_DeviceFlushEPqueue(XboxDeviceState* dev, USBEndpoint* ep);
//
// call usb class cancel_packet function
void USB_DeviceCancelPacket(XboxDeviceState* dev, USBPacket* p);
// Cancel an active packet. The packed must have been deferred by
// returning USB_RET_ASYNC from handle_packet, and not yet completed
void USB_CancelPacket(USBPacket* p);
// call usb class set_interface function
void USB_DeviceSetInterface(XboxDeviceState* dev, int iface, int alt_old, int alt_new);
// set the type of the endpoint
void USB_EPsetType(XboxDeviceState* dev, int pid, int ep, uint8_t type);
// set the interface number of the endpoint
uint8_t USB_EPsetIfnum(XboxDeviceState* dev, int pid, int ep, uint8_t ifnum);
// set the maximum packet size parameter of the endpoint
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);
};
#endif

View File

@ -102,21 +102,17 @@ struct USBDescOther {
const uint8_t* data;
};
/* Endpoint descriptor */
struct USBDescEndpoint {
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
uint8_t bRefresh;
uint8_t bSynchAddress;
uint8_t bEndpointAddress; // the address of the endpoint on the USB device described by this descriptor
uint8_t bmAttributes; // this field describes the endpoint's attributes when it is configured using the bConfigurationValue
uint16_t wMaxPacketSize; // maximum packet size this endpoint is capable of sending or receiving when this configuration is selected
uint8_t bInterval; // interval for polling endpoint for data transfers, expressed in milliseconds.
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;
/* superspeed endpoint companion */
uint8_t bMaxBurst;
uint8_t bmAttributes_super;
uint16_t wBytesPerInterval;
};
/* Interface descriptor */
@ -131,23 +127,16 @@ struct USBDescIface {
uint8_t ndesc;
USBDescOther* descs;
USBDescEndpoint* eps;
USBDescEndpoint* eps; // endpoints supported by this interface
USBDescIface(bool bDefault);
~USBDescIface();
};
/* conceptually an Interface Association Descriptor, and releated interfaces */
struct USBDescIfaceAssoc {
uint8_t bFirstInterface;
uint8_t bInterfaceCount;
uint8_t bFunctionClass;
uint8_t bFunctionSubClass;
uint8_t bFunctionProtocol;
uint8_t iFunction;
uint8_t nif;
const USBDescIface* ifs;
};
/*
* ergo720: I removed the Interface Association Descriptor (IAD) since, at the time of this writing (2018), the xboxdevwiki documents that all
* known xid devices don't use them and also, according to the corresponding standard, IAD applies to usb revision 2.0 while the xbox uses
* usb revision 1.1 so it shouldn't support them either. If this turns out to be incorrect, then IAD support will have to be added
*/
/* Configuration descriptor */
struct USBDescConfig {
@ -156,14 +145,8 @@ struct USBDescConfig {
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;
const USBDescIfaceAssoc* if_groups;
/* "normal" interfaces */
uint8_t nif;
const USBDescIface* ifs;
uint8_t nif; // number of interfaces (again)
const USBDescIface* ifs; // interfaces supported by this configuration
};
/* Device descriptor part 1 */
@ -174,7 +157,7 @@ struct USBDescDevice {
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
const USBDescConfig* confs; // configurations supported by this device
USBDescDevice(bool bDefault);
~USBDescDevice();
};
@ -198,13 +181,12 @@ struct USBDesc {
};
/* USB endpoint */
struct USBEndpoint
{
struct USBEndpoint {
uint8_t Num; // endpoint number
uint8_t pid;
uint8_t Type; // the type of this endpoint
uint8_t IfNum; // interface number this endpoint belongs to
int MaxPacketSize;
int MaxPacketSize; // maximum packet size supported by this endpoint
bool Pipeline;
bool Halted; // indicates that the endpoint is halted
XboxDeviceState* Dev; // device this endpoint belongs to
@ -212,8 +194,7 @@ struct USBEndpoint
};
/* definition of an Xbox usb device */
struct XboxDeviceState
{
struct XboxDeviceState {
USBPort* Port; // usb port struct of this device
int PortPath; // port index to which this device is attached to
char* Serial;
@ -239,14 +220,14 @@ struct XboxDeviceState
USBEndpoint EP_out[USB_MAX_ENDPOINTS]; // endpoints for IN tokens
QLIST_HEAD(, USBDescString) Strings; // strings of the string descriptor
const USBDesc* UsbDesc; // Overrides class usb_desc if not NULL
const USBDesc* UsbDesc; // Overrides class usb_desc if not nullptr
const USBDescDevice* Device; // device descriptor part 1
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];
int Configuration; // number of the selected configuration descriptor
int NumInterfaces; // number of available interface descriptors
int AltSetting[USB_MAX_INTERFACES]; // alternate setting numbers for the current interface
const USBDescConfig* Config; // configuration in use
const USBDescIface* Ifaces[USB_MAX_INTERFACES]; // interface in use
};
struct USBCombinedPacket {
@ -256,8 +237,7 @@ struct USBCombinedPacket {
};
/* Structure used to hold information about an active USB packet */
struct USBPacket
{
struct USBPacket {
int Pid; // Packet ID (used to identify the type of packet that is being sent)
uint32_t Id; // Paddr of the TD for this packet
USBEndpoint* Endpoint; // endpoint this packet is transferred to
@ -275,9 +255,26 @@ struct USBPacket
QTAILQ_ENTRY(USBPacket) CombinedEntry;
};
struct USBPortOps {
std::function<void(USBPort*port)> attach;
std::function<void(USBPort *port)> detach;
/*
* This gets called when a device downstream from the device attached to
* the port (attached through a hub) gets detached.
*/
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
* the packet originated when a hub is involved.
*/
std::function<void(USBPort* port, USBPacket* p)> complete;
};
/* Struct describing the status of a usb port */
struct USBPort {
XboxDeviceState* Dev; // usb device (if present)
USBPortOps* Operations; // functions to call when a port event happens
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
@ -285,8 +282,7 @@ struct USBPort {
};
/* Struct which stores general functions/variables regarding the peripheral */
struct USBDeviceClass
{
struct USBDeviceClass {
std::function<int(XboxDeviceState* dev)> init;
// Walk (enabled) downstream ports, check for a matching device.