mirror of
https://github.com/StrikerX3/StrikeBox.git
synced 2024-06-23 14:53:22 -04:00
Sync OHCI code up to Cxbx-R commit 169806b2
This is the latest OHCI related code. Nothing related to SDL2 was ported. Needs major improvements.
This commit is contained in:
parent
b81de821a9
commit
e1c24c52b9
|
@ -62,7 +62,7 @@ uint64_t GetTime_NS(TimerObject* Timer) {
|
|||
|
||||
// Calculates the next expire time of the timer
|
||||
static inline uint64_t GetNextExpireTime(TimerObject* Timer) {
|
||||
return GetTime_NS(Timer) + Timer->ExpireTime_MS.load() * SCALE_MS;
|
||||
return GetTime_NS(Timer) + Timer->ExpireTime_MS.load();
|
||||
}
|
||||
|
||||
// Deallocates the memory of the timer
|
||||
|
@ -123,6 +123,7 @@ TimerObject* Timer_Create(pTimerCB Callback, void* Arg, unsigned int Factor) {
|
|||
}
|
||||
|
||||
// Starts the timer
|
||||
// Expire_MS must be expressed in NS
|
||||
void Timer_Start(TimerObject* Timer, uint64_t Expire_MS) {
|
||||
Timer->ExpireTime_MS.store(Expire_MS);
|
||||
std::thread(ClockThread, Timer).detach();
|
||||
|
|
|
@ -140,7 +140,7 @@ static inline uint64_t Muldiv64(uint64_t a, uint32_t b, uint32_t c) {
|
|||
#define OHCI_ED_EN_MASK (0xF<<OHCI_ED_EN_SHIFT) // EndpointNumber
|
||||
#define OHCI_ED_D_SHIFT 11
|
||||
#define OHCI_ED_D_MASK (3<<OHCI_ED_D_SHIFT) // Direction
|
||||
#define OHCI_ED_S (1<<13)
|
||||
#define OHCI_ED_S (1<<13) // Speed
|
||||
#define OHCI_ED_K (1<<14) // sKip
|
||||
#define OHCI_ED_F (1<<15) // Format
|
||||
#define OHCI_ED_MPS_SHIFT 16
|
||||
|
@ -148,7 +148,7 @@ static inline uint64_t Muldiv64(uint64_t a, uint32_t b, uint32_t c) {
|
|||
|
||||
/* Flags in the HeadP field of an ED */
|
||||
#define OHCI_ED_H 1 // Halted
|
||||
#define OHCI_ED_C 2
|
||||
#define OHCI_ED_C 2 // toggleCarry
|
||||
|
||||
/* Bitfields for the first word of a TD */
|
||||
#define OHCI_TD_R (1<<18) // bufferRounding
|
||||
|
@ -159,7 +159,7 @@ static inline uint64_t Muldiv64(uint64_t a, uint32_t b, uint32_t c) {
|
|||
#define OHCI_TD_T0 (1<<24)
|
||||
#define OHCI_TD_T1 (1<<25) // DataToggle (T0 and T1)
|
||||
#define OHCI_TD_EC_SHIFT 26
|
||||
#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT)
|
||||
#define OHCI_TD_EC_MASK (3<<OHCI_TD_EC_SHIFT) // ErrorCount
|
||||
#define OHCI_TD_CC_SHIFT 28
|
||||
#define OHCI_TD_CC_MASK (0xF<<OHCI_TD_CC_SHIFT) // ConditionCode
|
||||
/* Bitfields for the first word of an Isochronous Transfer Desciptor. */
|
||||
|
@ -233,15 +233,15 @@ OHCI::OHCI(Cpu* cpu, int Irq, USBPCIDevice* UsbObj)
|
|||
}
|
||||
|
||||
if (m_IrqNum == 9) {
|
||||
offset = 2;
|
||||
offset = 4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m_UsbDevice->USB_RegisterPort(&m_Registers.RhPort[i].UsbPort, i + offset, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, ops);
|
||||
}
|
||||
OHCI_PacketInit(&m_UsbPacket);
|
||||
|
||||
m_UsbFrameTime = 1000000ULL; // 1 ms
|
||||
m_UsbFrameTime = 1000000ULL; // 1 ms expressed in ns
|
||||
m_TicksPerUsbTick = 1000000000ULL / USB_HZ; // 83
|
||||
|
||||
// Do a hardware reset
|
||||
|
@ -294,7 +294,8 @@ void OHCI::OHCI_FrameBoundaryWorker()
|
|||
|
||||
// From the standard: "This bit is loaded from the FrameIntervalToggle field of
|
||||
// HcFmInterval whenever FrameRemaining reaches 0."
|
||||
m_Registers.HcFmRemaining = (m_Registers.HcFmRemaining & ~OHCI_FMR_FRT) | (m_Registers.HcFmInterval & OHCI_FMI_FIT);
|
||||
m_Registers.HcFmRemaining = (m_Registers.HcFmInterval & OHCI_FMI_FIT) == 0 ?
|
||||
m_Registers.HcFmRemaining & ~OHCI_FMR_FRT : m_Registers.HcFmRemaining | OHCI_FMR_FRT;
|
||||
|
||||
// Increment frame number
|
||||
m_Registers.HcFmNumber = (m_Registers.HcFmNumber + 1) & 0xFFFF; // prevent overflow
|
||||
|
@ -341,7 +342,7 @@ void OHCI::OHCI_FatalError()
|
|||
{
|
||||
// According to the standard, an OHCI will stop operating, and set itself into error state
|
||||
// (which can be queried by MMIO). Instead of calling directly CxbxKrnlCleanup, we let the
|
||||
// HCD know the problem so it can try to solve it
|
||||
// HCD know the problem so that it can try to solve it
|
||||
|
||||
OHCI_SetInterrupt(OHCI_INTR_UE);
|
||||
OHCI_BusStop();
|
||||
|
@ -618,7 +619,7 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
addr = Ed->HeadP & OHCI_DPTR_MASK;
|
||||
// See if this TD has already been submitted to the device
|
||||
completion = (addr == m_AsyncTD);
|
||||
if (completion && !m_AsyncComplete) { // ??
|
||||
if (completion && !m_AsyncComplete) {
|
||||
#ifdef DEBUG_PACKET
|
||||
log_spew("OHCI: Skipping async TD\n");
|
||||
#endif
|
||||
|
@ -859,7 +860,7 @@ XboxDeviceState* OHCI::OHCI_FindDevice(uint8_t Addr)
|
|||
XboxDeviceState* dev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((m_Registers.RhPort[i].HcRhPortStatus & OHCI_PORT_PES) == 0) {
|
||||
continue; // port is disabled
|
||||
}
|
||||
|
@ -881,13 +882,8 @@ void OHCI::OHCI_StateReset()
|
|||
m_OldHcControl = 0;
|
||||
|
||||
// Reset all registers
|
||||
// Remark: the standard says that RemoteWakeupConnected bit should be set during POST, cleared during hw reset
|
||||
// and ignored during a sw reset. However, VBox sets it on hw reset and XQEMU clears it. Considering that the Xbox
|
||||
// doesn't do POST, I will clear it.
|
||||
m_Registers.HcRevision = 0x10;
|
||||
m_Registers.HcControl = 0;
|
||||
m_Registers.HcControl &= ~OHCI_CTL_HCFS;
|
||||
m_Registers.HcControl |= Reset;
|
||||
m_Registers.HcCommandStatus = 0;
|
||||
m_Registers.HcInterruptStatus = 0;
|
||||
m_Registers.HcInterrupt = OHCI_INTR_MIE; // enable interrupts
|
||||
|
@ -906,13 +902,13 @@ void OHCI::OHCI_StateReset()
|
|||
m_Registers.HcPeriodicStart = 0;
|
||||
m_Registers.HcLSThreshold = OHCI_LS_THRESH;
|
||||
|
||||
m_Registers.HcRhDescriptorA = OHCI_RHA_NPS | 2; // The xbox lacks the hw to switch off the power on the ports and has 2 ports per HC
|
||||
m_Registers.HcRhDescriptorA = OHCI_RHA_NOCP | OHCI_RHA_NPS | 4; // The xbox lacks the hw to switch off the power on the ports and has 4 ports per HC
|
||||
m_Registers.HcRhDescriptorB = 0; // The attached devices are removable and use PowerSwitchingMode to control the power on the ports
|
||||
m_Registers.HcRhStatus = 0;
|
||||
|
||||
m_DoneCount = 7;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
OHCIPort* Port = &m_Registers.RhPort[i];
|
||||
Port->HcRhPortStatus = 0;
|
||||
|
@ -1109,6 +1105,14 @@ uint32_t OHCI::OHCI_ReadRegister(uint32_t Addr)
|
|||
ret = m_Registers.RhPort[1].HcRhPortStatus | OHCI_PORT_PPS;
|
||||
break;
|
||||
|
||||
case 23: // RhPort 2
|
||||
ret = m_Registers.RhPort[2].HcRhPortStatus | OHCI_PORT_PPS;
|
||||
break;
|
||||
|
||||
case 24: // RhPort 3
|
||||
ret = m_Registers.RhPort[3].HcRhPortStatus | OHCI_PORT_PPS;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning("OHCI: Read register operation with bad offset %u. Ignoring.\n", Addr >> 2);
|
||||
}
|
||||
|
@ -1240,6 +1244,14 @@ void OHCI::OHCI_WriteRegister(uint32_t Addr, uint32_t Value)
|
|||
OHCI_PortSetStatus(1, Value);
|
||||
break;
|
||||
|
||||
case 23: // RhPort 2
|
||||
OHCI_PortSetStatus(2, Value);
|
||||
break;
|
||||
|
||||
case 24: // RhPort 3
|
||||
OHCI_PortSetStatus(3, Value);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_warning("OHCI: Write register operation with bad offset %u. Ignoring.\n", Addr >> 2);
|
||||
}
|
||||
|
@ -1250,11 +1262,9 @@ void OHCI::OHCI_UpdateInterrupt()
|
|||
{
|
||||
// TODO: interrupts
|
||||
if ((m_Registers.HcInterrupt & OHCI_INTR_MIE) && (m_Registers.HcInterruptStatus & m_Registers.HcInterrupt)) {
|
||||
//HalSystemInterrupts[m_IrqNum].Assert(false);
|
||||
//HalSystemInterrupts[m_IrqNum].Assert(true);
|
||||
}
|
||||
else {
|
||||
//HalSystemInterrupts[m_IrqNum].Assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void OHCI::OHCI_SetInterrupt(uint32_t Value)
|
||||
|
@ -1291,7 +1301,7 @@ void OHCI::OHCI_StopEndpoints()
|
|||
XboxDeviceState* dev;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
dev = m_Registers.RhPort[i].UsbPort.Dev;
|
||||
if (dev && dev->Attached) {
|
||||
m_UsbDevice->USB_DeviceEPstopped(dev, &dev->EP_ctl);
|
||||
|
@ -1317,7 +1327,7 @@ void OHCI::OHCI_SetHubStatus(uint32_t Value)
|
|||
if (Value & OHCI_RHS_LPS) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
OHCI_PortPower(i, 0);
|
||||
}
|
||||
log_debug("OHCI: powered down all ports\n");
|
||||
|
@ -1326,7 +1336,7 @@ void OHCI::OHCI_SetHubStatus(uint32_t Value)
|
|||
if (Value & OHCI_RHS_LPSC) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
OHCI_PortPower(i, 1);
|
||||
}
|
||||
log_debug("OHCI: powered up all ports\n");
|
||||
|
@ -1525,7 +1535,7 @@ void OHCI::OHCI_AsyncCancelDevice(XboxDeviceState* dev)
|
|||
m_UsbDevice->USB_IsPacketInflight(&m_UsbPacket) &&
|
||||
m_UsbPacket.Endpoint->Dev == dev) {
|
||||
m_UsbDevice->USB_CancelPacket(&m_UsbPacket);
|
||||
m_AsyncTD = 0;
|
||||
m_AsyncTD = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ using namespace openxbox::cpu;
|
|||
// EOF: end of frame; the end of a USB-defined frame
|
||||
// ED: endpoint descriptor; a memory structure used by the HC to communicate with an endpoint
|
||||
// TD: transfer descriptor; a memory structure used by the HC to transfer a block of data to/from a device endpoint
|
||||
// HCCA: Host Controller Communications Area; shared memory between the HC and HCD
|
||||
|
||||
|
||||
/* endpoint descriptor */
|
||||
|
@ -135,7 +136,7 @@ struct OHCI_Registers {
|
|||
uint32_t HcRhDescriptorA;
|
||||
uint32_t HcRhDescriptorB;
|
||||
uint32_t HcRhStatus;
|
||||
OHCIPort RhPort[2]; // 2 ports per HC, for a total of 4 USB ports
|
||||
OHCIPort RhPort[4]; // 4 ports per HC
|
||||
};
|
||||
|
||||
|
||||
|
@ -143,7 +144,7 @@ struct OHCI_Registers {
|
|||
class OHCI {
|
||||
public:
|
||||
// Indicates that the timer thread is accessing the OHCI object. Necessary because the input thread from the
|
||||
// InputDeviceManager will access us when it needs to destroy a device
|
||||
// InputDeviceManager will access us when it needs to create or destroy a device
|
||||
std::atomic_bool m_bFrameTime;
|
||||
|
||||
// constructor
|
||||
|
@ -159,7 +160,7 @@ private:
|
|||
Cpu* m_cpu;
|
||||
// pointer to g_USB0 or g_USB1
|
||||
USBPCIDevice* m_UsbDevice = nullptr;
|
||||
// all the registers available on the OHCI standard
|
||||
// all the registers available in the OHCI standard
|
||||
OHCI_Registers m_Registers;
|
||||
// end-of-frame timer
|
||||
TimerObject* m_pEOFtimer = nullptr;
|
||||
|
@ -181,8 +182,8 @@ private:
|
|||
int m_DoneCount;
|
||||
// the address of the pending TD
|
||||
uint32_t m_AsyncTD = NULL;
|
||||
// ergo720: I think it signals that a TD has been processed completely
|
||||
bool m_AsyncComplete;
|
||||
// indicates if there is a pending asynchronous packet to process
|
||||
bool m_AsyncComplete = 0;
|
||||
|
||||
// EOF callback wrapper
|
||||
static void OHCI_FrameBoundaryWrapper(void* pVoid);
|
||||
|
@ -248,7 +249,7 @@ private:
|
|||
// process an isochronous TD
|
||||
int OHCI_ServiceIsoTD(OHCI_ED* ed, int completion);
|
||||
// find the usb device with the supplied address
|
||||
XboxDeviceState* OHCI::OHCI_FindDevice(uint8_t Addr);
|
||||
XboxDeviceState* OHCI_FindDevice(uint8_t Addr);
|
||||
// cancel a packet when a device is removed
|
||||
void OHCI_AsyncCancelDevice(XboxDeviceState* dev);
|
||||
// Process Control and Bulk lists
|
||||
|
|
|
@ -158,12 +158,14 @@ typedef enum {
|
|||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT,
|
||||
STR_SERIALNUMBER,
|
||||
};
|
||||
} STRING_DESC_INDEX;
|
||||
|
||||
// Forward declarations
|
||||
struct USBPacket;
|
||||
struct USBPort;
|
||||
struct USBDeviceClass;
|
||||
struct XboxDeviceState;
|
||||
struct USBPortOps;
|
||||
|
||||
/* String descriptor */
|
||||
struct USBDescString {
|
||||
|
@ -206,9 +208,7 @@ struct USBDescIface {
|
|||
|
||||
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();
|
||||
~USBDescIface();
|
||||
const USBDescEndpoint* eps; // endpoints supported by this interface
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -239,8 +239,6 @@ struct USBDescDevice {
|
|||
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; // configurations supported by this device
|
||||
USBDescDevice();
|
||||
~USBDescDevice();
|
||||
};
|
||||
|
||||
/* Device descriptor part 2 */
|
||||
|
@ -258,7 +256,6 @@ struct USBDesc {
|
|||
USBDescID id; // id-specific info of the device descriptor
|
||||
const USBDescDevice* full; // remaining fields of the device descriptor
|
||||
const char* const* str;
|
||||
USBDesc();
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
|
@ -332,91 +329,13 @@ struct USBEndpoint {
|
|||
QTAILQ_HEAD(, USBPacket) Queue; // queue of packets to this endpoint
|
||||
};
|
||||
|
||||
/* definition of an Xbox usb device */
|
||||
struct XboxDeviceState {
|
||||
USBPort* Port; // usb port struct of this device
|
||||
int PortPath; // port index to which this device is attached to
|
||||
uint32_t flags;
|
||||
USBDeviceClass* klass; // usb class struct of this device
|
||||
|
||||
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]; // 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 control transfer processing operation
|
||||
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 descriptors
|
||||
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]; // alternate setting numbers for the current interface
|
||||
const USBDescConfig* Config; // configuration descriptor in use
|
||||
const USBDescIface* Ifaces[USB_MAX_INTERFACES]; // interface in use
|
||||
};
|
||||
|
||||
struct USBCombinedPacket {
|
||||
USBPacket* First;
|
||||
QTAILQ_HEAD(packets_head, USBPacket) Packets;
|
||||
IOVector IoVec;
|
||||
};
|
||||
|
||||
/* Structure used to hold information about an active USB packet */
|
||||
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
|
||||
unsigned int Stream;
|
||||
IOVector IoVec; // used to perform vectored I/O
|
||||
uint64_t Parameter; // control transfers
|
||||
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; // number of bytes actually written to DataBuffer
|
||||
// Internal use by the USB layer
|
||||
USBPacketState State;
|
||||
USBCombinedPacket* Combined;
|
||||
QTAILQ_ENTRY(USBPacket) Queue;
|
||||
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 = nullptr; // usb device (if present)
|
||||
USBPortOps* Operations = nullptr; // functions to call when a port event happens
|
||||
int SpeedMask; // usb speeds supported
|
||||
int HubCount; // number of hubs chained
|
||||
std::string Path; // the number of the port + 1, used to create a serial number for this device
|
||||
int PortIndex; // internal port index
|
||||
XboxDeviceState* Dev = nullptr; // usb device(if present)
|
||||
USBPortOps* Operations; // functions to call when a port event happens
|
||||
int SpeedMask; // usb speeds supported
|
||||
std::string Path; // the number of the port + 1, used to create a serial number for this device
|
||||
int PortIndex; // internal port index
|
||||
};
|
||||
|
||||
/* Struct which stores general functions/variables regarding the peripheral */
|
||||
|
@ -467,4 +386,73 @@ struct USBDeviceClass {
|
|||
const USBDesc* usb_desc; // device descriptor
|
||||
};
|
||||
|
||||
/* definition of an Xbox usb device */
|
||||
struct XboxDeviceState {
|
||||
USBPort* Port; // usb port struct of this device
|
||||
int PortPath; // port index to which this device is attached to
|
||||
uint32_t flags;
|
||||
USBDeviceClass* klass; // usb class struct of this device
|
||||
|
||||
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]; // 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 control transfer processing operation
|
||||
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 descriptors
|
||||
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]; // alternate setting numbers for the current interface
|
||||
const USBDescConfig* Config; // configuration descriptor in use
|
||||
const USBDescIface* Ifaces[USB_MAX_INTERFACES]; // interface in use
|
||||
};
|
||||
|
||||
/* Structure used to hold information about an active USB packet */
|
||||
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
|
||||
unsigned int Stream;
|
||||
IOVector IoVec; // used to perform vectored I/O
|
||||
uint64_t Parameter; // this seems to be used only in xhci and it's 0 otherwise. If so, this can be removed
|
||||
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; // number of bytes actually written to DataBuffer
|
||||
// Internal use by the USB layer
|
||||
USBPacketState State;
|
||||
QTAILQ_ENTRY(USBPacket) Queue;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -49,57 +49,61 @@ namespace openxbox {
|
|||
|
||||
Hub* g_HubObjArray[4] = { nullptr };
|
||||
|
||||
USBDescIface::USBDescIface() {
|
||||
std::memset(this, 0, sizeof(USBDescIface));
|
||||
eps = new USBDescEndpoint();
|
||||
bInterfaceNumber = 0;
|
||||
bNumEndpoints = 1;
|
||||
bInterfaceClass = USB_CLASS_HUB;
|
||||
eps->bEndpointAddress = USB_DIR_IN | 0x01;
|
||||
eps->bmAttributes = USB_ENDPOINT_XFER_INT;
|
||||
eps->wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8;
|
||||
eps->bInterval = 0xFF;
|
||||
}
|
||||
static const USBDescEndpoint desc_endp_hub = {
|
||||
USB_DIR_IN | 0x01, // bEndpointAddress;
|
||||
USB_ENDPOINT_XFER_INT, // bmAttributes;
|
||||
1 + (NUM_PORTS + 7) / 8, // wMaxPacketSize;
|
||||
0xFF, // bInterval;
|
||||
0, // bRefresh;
|
||||
0, // bSynchAddress
|
||||
0, // is_audio
|
||||
nullptr // extra
|
||||
};
|
||||
|
||||
USBDescIface::~USBDescIface() {
|
||||
delete eps;
|
||||
}
|
||||
static const USBDescIface desc_iface_hub = {
|
||||
0, // bInterfaceNumber;
|
||||
0, // bAlternateSetting;
|
||||
1, // bNumEndpoints;
|
||||
USB_CLASS_HUB, // bInterfaceClass;
|
||||
0, // bInterfaceSubClass
|
||||
0, // bInterfaceProtocol
|
||||
0, // iInterface
|
||||
0, // ndesc
|
||||
nullptr, // descs
|
||||
&desc_endp_hub
|
||||
};
|
||||
|
||||
static const USBDescIface desc_iface_hub;
|
||||
static const USBDescConfig desc_config_hub = {
|
||||
1, // bNumInterfaces
|
||||
1, // bConfigurationValue
|
||||
0, // iConfiguration
|
||||
0xE0, // bmAttributes
|
||||
0, // bMaxPower
|
||||
1, // nif
|
||||
&desc_iface_hub
|
||||
};
|
||||
|
||||
USBDescDevice::USBDescDevice() {
|
||||
std::memset(this, 0, sizeof(USBDescDevice));
|
||||
USBDescConfig* pUSBDescConfig = new USBDescConfig();
|
||||
bcdUSB = 0x0110;
|
||||
bDeviceClass = USB_CLASS_HUB;
|
||||
bMaxPacketSize0 = 8;
|
||||
bNumConfigurations = 1;
|
||||
pUSBDescConfig->bNumInterfaces = 1;
|
||||
pUSBDescConfig->bConfigurationValue = 1;
|
||||
pUSBDescConfig->bmAttributes = 0xE0;
|
||||
pUSBDescConfig->nif = 1;
|
||||
pUSBDescConfig->ifs = &desc_iface_hub;
|
||||
confs = pUSBDescConfig;
|
||||
}
|
||||
static const USBDescDevice desc_device_hub = {
|
||||
0x0110, // bcdUSB
|
||||
USB_CLASS_HUB, // bDeviceClass
|
||||
0, // bDeviceSubClass
|
||||
0, // bDeviceProtocol
|
||||
8, // bMaxPacketSize0
|
||||
1, // bNumConfigurations
|
||||
&desc_config_hub
|
||||
};
|
||||
|
||||
USBDescDevice::~USBDescDevice() {
|
||||
delete confs;
|
||||
}
|
||||
|
||||
static const USBDescDevice desc_device_hub;
|
||||
|
||||
USBDesc::USBDesc() {
|
||||
std::memset(this, 0, sizeof(USBDesc));
|
||||
id.idVendor = 0x0409;
|
||||
id.idProduct = 0x55AA;
|
||||
id.bcdDevice = 0x0101;
|
||||
id.iManufacturer = STR_MANUFACTURER;
|
||||
id.iProduct = STR_PRODUCT;
|
||||
id.iSerialNumber = STR_SERIALNUMBER;
|
||||
full = &desc_device_hub;
|
||||
}
|
||||
|
||||
static const USBDesc desc_hub;
|
||||
static const USBDesc desc_hub = {
|
||||
{
|
||||
0x0409, // idVendor
|
||||
0x55AA, // idProduct
|
||||
0x0101, // bcdDevice
|
||||
STR_MANUFACTURER, // iManufacturer
|
||||
STR_PRODUCT, // iProduct
|
||||
STR_SERIALNUMBER // iSerialNumber
|
||||
},
|
||||
&desc_device_hub
|
||||
};
|
||||
|
||||
// Class-specific hub descriptor. Remember to update DeviceRemovable and PortPwrCtrlMask if you change NUM_PORTS since their values depend on
|
||||
// the number of downstream ports available on the hub! Also note that this descriptor cannot be put in the descs member of the interface descriptor
|
||||
|
@ -125,11 +129,15 @@ int Hub::Init(int port) {
|
|||
XboxDeviceState* dev = ClassInitFn();
|
||||
int rc = UsbHubClaimPort(dev, port);
|
||||
if (rc != 0) {
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_EpInit(dev);
|
||||
m_UsbDev->USB_DeviceInit(dev);
|
||||
m_UsbDev->USB_DeviceAttach(dev);
|
||||
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -165,24 +173,27 @@ int Hub::UsbHubClaimPort(XboxDeviceState* dev, int port) {
|
|||
assert(dev->Port == nullptr);
|
||||
|
||||
if (port > 2) {
|
||||
//m_UsbDev = g_USB0; // FIXME: how to retrieve these?
|
||||
}
|
||||
else {
|
||||
//m_UsbDev = g_USB1; // FIXME: how to retrieve these?
|
||||
}
|
||||
else {
|
||||
//m_UsbDev = g_USB0; // FIXME: how to retrieve these?
|
||||
}
|
||||
|
||||
while (m_UsbDev->m_HostController->m_bFrameTime) {}
|
||||
m_UsbDev->m_HostController->m_bFrameTime = true;
|
||||
|
||||
i = 0;
|
||||
for (auto usb_port : m_UsbDev->m_FreePorts) {
|
||||
if (usb_port->Path == std::to_string(port)) {
|
||||
it = m_UsbDev->m_FreePorts.begin() + i;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i == 2) {
|
||||
if (it == m_UsbDev->m_FreePorts.end()) {
|
||||
log_warning("OHCI: Port requested %d not found (in use?)", port);
|
||||
return -1;
|
||||
}
|
||||
it = m_UsbDev->m_FreePorts.begin() + i;
|
||||
dev->Port = *it;
|
||||
(*it)->Dev = dev;
|
||||
m_UsbDev->m_FreePorts.erase(it);
|
||||
|
|
|
@ -203,10 +203,9 @@ void USBPCIDevice::USB_PacketSetup(USBPacket* p, int Pid, USBEndpoint* Ep, unsig
|
|||
p->Stream = Stream;
|
||||
p->Status = USB_RET_SUCCESS;
|
||||
p->ActualLength = 0;
|
||||
p->Parameter = 0;
|
||||
p->Parameter = 0ull;
|
||||
p->ShortNotOK = ShortNotOK;
|
||||
p->IntReq = IntReq;
|
||||
p->Combined = nullptr;
|
||||
IoVecReset(&p->IoVec);
|
||||
p->State = USB_PACKET_SETUP;
|
||||
}
|
||||
|
@ -495,7 +494,7 @@ void USBPCIDevice::DoTokenOut(XboxDeviceState* s, USBPacket* p) {
|
|||
}
|
||||
|
||||
void USBPCIDevice::USB_PacketCopy(USBPacket* p, void* ptr, size_t bytes) {
|
||||
IOVector* iov = p->Combined ? &p->Combined->IoVec : &p->IoVec;
|
||||
IOVector* iov = &p->IoVec;
|
||||
|
||||
assert(p->ActualLength >= 0);
|
||||
assert(p->ActualLength + bytes <= iov->Size);
|
||||
|
@ -705,7 +704,6 @@ void USBPCIDevice::USB_EpReset(XboxDeviceState* dev) {
|
|||
void USBPCIDevice::USB_CreateSerial(XboxDeviceState* dev, std::string&& str) {
|
||||
const USBDesc* desc = USBDesc_GetUsbDeviceDesc(dev);
|
||||
int index = desc->id.iSerialNumber;
|
||||
std::string str2;
|
||||
|
||||
assert(index != 0 && str.empty() == false);
|
||||
str += '-';
|
||||
|
@ -1009,7 +1007,7 @@ int USBPCIDevice::USBDesc_HandleStandardGetDescriptor(XboxDeviceState* dev, USBP
|
|||
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,
|
||||
// Dropped from XQEMU descriptor types USB_DT_DEVICE_QUALIFIER (6), USB_DT_OTHER_SPEED_CONFIG (7) -> usb 2.0 only and reserved in usb 3.0,
|
||||
// USB_DT_BOS (15) and USB_DT_DEBUG (10) -> usb 3.0 only
|
||||
|
||||
default:
|
||||
|
@ -1143,8 +1141,8 @@ int USBPCIDevice::USB_ReadInterfaceDesc(const USBDescIface* iface, int flags, ui
|
|||
return pos;
|
||||
}
|
||||
|
||||
int USBPCIDevice::USB_ReadOtherDesc(const USBDescOther* desc, uint8_t* dest, size_t len) {
|
||||
int bLength = desc->length ? desc->length : desc->data[0];
|
||||
size_t USBPCIDevice::USB_ReadOtherDesc(const USBDescOther* desc, uint8_t* dest, size_t len) {
|
||||
size_t bLength = desc->length ? desc->length : desc->data[0];
|
||||
|
||||
if (len < bLength) {
|
||||
return -1;
|
||||
|
@ -1155,15 +1153,15 @@ int USBPCIDevice::USB_ReadOtherDesc(const USBDescOther* desc, uint8_t* dest, siz
|
|||
}
|
||||
|
||||
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;
|
||||
size_t bLength = ep->is_audio ? 0x09 : 0x07; // an endpoint descriptor is 7 bytes large (or 9 if it is an audio device)
|
||||
size_t extralen = ep->extra ? ep->extra[0] : 0;
|
||||
USBDescriptor* d = reinterpret_cast<USBDescriptor*>(dest);
|
||||
|
||||
if (len < bLength + extralen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
d->bLength = bLength;
|
||||
d->bLength = static_cast<uint8_t>(bLength);
|
||||
d->bDescriptorType = USB_DT_ENDPOINT;
|
||||
|
||||
d->u.endpoint.bEndpointAddress = ep->bEndpointAddress;
|
||||
|
@ -1186,7 +1184,8 @@ int USBPCIDevice::USB_ReadEndpointDesc(const USBDescEndpoint* ep, int flags, uin
|
|||
}
|
||||
|
||||
int USBPCIDevice::USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* dest, size_t len) {
|
||||
uint8_t bLength, pos, i;
|
||||
size_t bLength, i;
|
||||
unsigned int pos;
|
||||
const char* str;
|
||||
|
||||
if (len < 4) {
|
||||
|
@ -1213,7 +1212,7 @@ int USBPCIDevice::USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* d
|
|||
// 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;
|
||||
bLength = std::strlen(str) * 2 + 2;
|
||||
dest[0] = bLength;
|
||||
dest[1] = USB_DT_STRING;
|
||||
i = 0; pos = 2;
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
void USB_PacketCheckState(USBPacket* p, USBPacketState expected);
|
||||
// process the packet
|
||||
void USB_ProcessOne(USBPacket* p);
|
||||
//
|
||||
// xhci only?
|
||||
void USB_DoParameter(XboxDeviceState* s, USBPacket* p);
|
||||
// process a setup token
|
||||
void USB_DoTokenSetup(XboxDeviceState* s, USBPacket* p);
|
||||
|
@ -196,7 +196,7 @@ public:
|
|||
// 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);
|
||||
size_t 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
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
// ******************************************************************
|
||||
|
||||
#include "xid_gamepad.h"
|
||||
#include "..\ohci\ohci.h"
|
||||
#include "../pci/usb_pci.h"
|
||||
|
||||
#include <string>
|
||||
|
@ -67,7 +68,6 @@ struct XIDDesc {
|
|||
uint8_t bMaxInputReportSize;
|
||||
uint8_t bMaxOutputReportSize;
|
||||
uint16_t wAlternateProductIds[4];
|
||||
XIDDesc();
|
||||
};
|
||||
|
||||
/* Struct used by the Get_Report request -> state of the buttons */
|
||||
|
@ -98,97 +98,104 @@ struct USBXIDState {
|
|||
|
||||
const XIDDesc* xid_desc; // xid-specific descriptor
|
||||
|
||||
bool in_dirty; // indicates a change in the button's state
|
||||
XIDGamepadReport in_state; // Get_Report struct
|
||||
XIDGamepadOutputReport out_state; // Ser_Report struct
|
||||
XIDGamepadReport in_state; // Get_Report struct
|
||||
XIDGamepadReport in_state_capabilities; // Get_Capabilities struct (in)
|
||||
XIDGamepadOutputReport out_state; // Set_Report struct
|
||||
XIDGamepadOutputReport out_state_capabilities; // Get_Capabilities struct (out)
|
||||
};
|
||||
|
||||
USBDescIface::USBDescIface() {
|
||||
std::memset(this, 0, sizeof(USBDescIface));
|
||||
eps = new USBDescEndpoint[2]();
|
||||
bInterfaceNumber = 0;
|
||||
bNumEndpoints = 2;
|
||||
bInterfaceClass = USB_CLASS_XID;
|
||||
bInterfaceSubClass = 0x42;
|
||||
bInterfaceProtocol = 0x00;
|
||||
eps->bEndpointAddress = USB_DIR_IN | 0x02;
|
||||
eps->bmAttributes = USB_ENDPOINT_XFER_INT;
|
||||
eps->wMaxPacketSize = 0x20;
|
||||
eps->bInterval = 4;
|
||||
eps++;
|
||||
eps->bEndpointAddress = USB_DIR_OUT | 0x02;
|
||||
eps->bmAttributes = USB_ENDPOINT_XFER_INT;
|
||||
eps->wMaxPacketSize = 0x20;
|
||||
eps->bInterval = 4;
|
||||
}
|
||||
static const USBDescEndpoint desc_endp_xbox_gamepad[2] = {
|
||||
{
|
||||
USB_DIR_IN | 0x02, // bEndpointAddress;
|
||||
USB_ENDPOINT_XFER_INT, // bmAttributes;
|
||||
0x20, // wMaxPacketSize;
|
||||
4, // bInterval;
|
||||
0, // bRefresh;
|
||||
0, // bSynchAddress
|
||||
0, // is_audio
|
||||
nullptr // extra
|
||||
},
|
||||
{
|
||||
USB_DIR_OUT | 0x02,
|
||||
USB_ENDPOINT_XFER_INT,
|
||||
0x20,
|
||||
4,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr
|
||||
}
|
||||
};
|
||||
|
||||
USBDescIface::~USBDescIface() {
|
||||
delete[] eps;
|
||||
}
|
||||
static const USBDescIface desc_iface_xbox_gamepad = {
|
||||
0, // bInterfaceNumber;
|
||||
0, // bAlternateSetting;
|
||||
2, // bNumEndpoints;
|
||||
USB_CLASS_XID, // bInterfaceClass;
|
||||
0x42, // bInterfaceSubClass
|
||||
0x00, // bInterfaceProtocol
|
||||
0, // iInterface
|
||||
0, // ndesc
|
||||
nullptr, // descs
|
||||
desc_endp_xbox_gamepad
|
||||
};
|
||||
|
||||
static const USBDescIface desc_iface_xbox_gamepad;
|
||||
static const USBDescConfig desc_config_xbox_gamepad = {
|
||||
1, // bNumInterfaces
|
||||
1, // bConfigurationValue
|
||||
0, // iConfiguration
|
||||
0x80, // bmAttributes
|
||||
50, // bMaxPower
|
||||
1, // nif
|
||||
&desc_iface_xbox_gamepad
|
||||
};
|
||||
|
||||
USBDescDevice::USBDescDevice() {
|
||||
std::memset(this, 0, sizeof(USBDescDevice));
|
||||
USBDescConfig* pUSBDescConfig = new USBDescConfig();
|
||||
bcdUSB = 0x0110;
|
||||
bMaxPacketSize0 = 0x40;
|
||||
bNumConfigurations = 1;
|
||||
pUSBDescConfig->bNumInterfaces = 1;
|
||||
pUSBDescConfig->bConfigurationValue = 1;
|
||||
pUSBDescConfig->bmAttributes = 0x80;
|
||||
pUSBDescConfig->bMaxPower = 50;
|
||||
pUSBDescConfig->nif = 1;
|
||||
pUSBDescConfig->ifs = &desc_iface_xbox_gamepad;
|
||||
confs = pUSBDescConfig;
|
||||
}
|
||||
static const USBDescDevice desc_device_xbox_gamepad = {
|
||||
0x0110, // bcdUSB
|
||||
0, // bDeviceClass
|
||||
0, // bDeviceSubClass
|
||||
0, // bDeviceProtocol
|
||||
0x40, // bMaxPacketSize0
|
||||
1, // bNumConfigurations
|
||||
&desc_config_xbox_gamepad
|
||||
};
|
||||
|
||||
USBDescDevice::~USBDescDevice() {
|
||||
delete confs;
|
||||
}
|
||||
static const USBDesc desc_xbox_gamepad = {
|
||||
{
|
||||
0x045E, // idVendor
|
||||
0x0202, // idProduct
|
||||
0x0100, // bcdDevice
|
||||
STR_MANUFACTURER, // iManufacturer
|
||||
STR_PRODUCT, // iProduct
|
||||
STR_SERIALNUMBER // iSerialNumber
|
||||
},
|
||||
&desc_device_xbox_gamepad
|
||||
};
|
||||
|
||||
static const USBDescDevice desc_device_xbox_gamepad;
|
||||
|
||||
USBDesc::USBDesc() {
|
||||
std::memset(this, 0, sizeof(USBDesc));
|
||||
id.idVendor = 0x045E;
|
||||
id.idProduct = 0x0202;
|
||||
id.bcdDevice = 0x0100;
|
||||
id.iManufacturer = STR_MANUFACTURER;
|
||||
id.iProduct = STR_PRODUCT;
|
||||
id.iSerialNumber = STR_SERIALNUMBER;
|
||||
full = &desc_device_xbox_gamepad;
|
||||
}
|
||||
|
||||
static const USBDesc desc_xbox_gamepad;
|
||||
|
||||
XIDDesc::XIDDesc() {
|
||||
bLength = 0x10;
|
||||
bDescriptorType = USB_DT_XID;
|
||||
bcdXid = 1;
|
||||
bType = 1;
|
||||
bSubType = 1;
|
||||
bMaxInputReportSize = 0x20;
|
||||
bMaxOutputReportSize = 0x6;
|
||||
wAlternateProductIds[0] = -1;
|
||||
wAlternateProductIds[1] = -1;
|
||||
wAlternateProductIds[2] = -1;
|
||||
wAlternateProductIds[3] = -1;
|
||||
}
|
||||
|
||||
static const XIDDesc desc_xid_xbox_gamepad;
|
||||
static const XIDDesc desc_xid_xbox_gamepad = {
|
||||
0x10, // bLength
|
||||
USB_DT_XID, // bDescriptorType
|
||||
0x100, // bcdXid
|
||||
1, // bType
|
||||
1, // bSubType
|
||||
20, // bMaxInputReportSize
|
||||
6, // bMaxOutputReportSize
|
||||
{ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF } // wAlternateProductIds
|
||||
};
|
||||
|
||||
int XidGamepad::Init(int port) {
|
||||
if (port > 4 || port < 1) { return -1; };
|
||||
if (port > 4 || port < 1) { return -1; }
|
||||
|
||||
XboxDeviceState* dev = ClassInitFn();
|
||||
int rc = UsbXidClaimPort(dev, port);
|
||||
if (rc != 0) {
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_EpInit(dev);
|
||||
m_UsbDev->USB_DeviceInit(dev);
|
||||
m_UsbDev->USB_DeviceAttach(dev);
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -241,6 +248,10 @@ int XidGamepad::UsbXidClaimPort(XboxDeviceState* dev, int port) {
|
|||
log_warning("XID: Port requested %d.2 not found (in use?)", port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (m_UsbDev->m_HostController->m_bFrameTime) {}
|
||||
m_UsbDev->m_HostController->m_bFrameTime = true;
|
||||
|
||||
m_Port = port;
|
||||
it = m_UsbDev->m_FreePorts.begin() + i;
|
||||
dev->Port = *it;
|
||||
|
@ -267,7 +278,17 @@ int XidGamepad::UsbXid_Initfn(XboxDeviceState* dev) {
|
|||
m_XidState->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 2);
|
||||
|
||||
m_XidState->in_state.bLength = sizeof(m_XidState->in_state);
|
||||
m_XidState->in_state.bReportId = 0;
|
||||
m_XidState->out_state.length = sizeof(m_XidState->out_state);
|
||||
m_XidState->out_state.report_id = 0;
|
||||
|
||||
std::memset(&m_XidState->in_state_capabilities, 0xFF, sizeof(m_XidState->in_state_capabilities));
|
||||
m_XidState->in_state_capabilities.bLength = sizeof(m_XidState->in_state_capabilities);
|
||||
m_XidState->in_state_capabilities.bReportId = 0;
|
||||
std::memset(&m_XidState->out_state_capabilities, 0xFF, sizeof(m_XidState->out_state_capabilities));
|
||||
m_XidState->out_state_capabilities.length = sizeof(m_XidState->out_state_capabilities);
|
||||
m_XidState->out_state_capabilities.report_id = 0;
|
||||
|
||||
m_XidState->xid_desc = &desc_xid_xbox_gamepad;
|
||||
|
||||
return 0;
|
||||
|
@ -308,21 +329,37 @@ void XidGamepad::UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
|||
// The wValue field specifies the Report Type in the high byte and the Report ID in the low byte. Set Report ID
|
||||
// to 0 (zero) if Report IDs are not used. 01 = input, 02 = output, 03 = feature, 04-FF = reserved"
|
||||
log_debug("XID: Gamepad GET_REPORT 0x%X", value);
|
||||
if (value == 0x100) {
|
||||
assert(m_XidState->in_state.bLength <= length);
|
||||
// m_XidState->in_state.bReportId++; /* FIXME: I'm not sure if bReportId is just a counter */
|
||||
// TODO: implement input devices
|
||||
/*SDL2Devices* controller = g_InputDeviceManager->FindDeviceFromXboxPort(m_Port);
|
||||
if (controller != nullptr) {
|
||||
controller->ReadButtonState(&m_XidState->in_state.wButtons, m_XidState->in_state.bAnalogButtons,
|
||||
&m_XidState->in_state.sThumbLX, &m_XidState->in_state.sThumbLY, &m_XidState->in_state.sThumbRX,
|
||||
&m_XidState->in_state.sThumbRY);
|
||||
}*/
|
||||
std::memcpy(data, &m_XidState->in_state, m_XidState->in_state.bLength);
|
||||
p->ActualLength = m_XidState->in_state.bLength;
|
||||
// JayFoxRox's analysis: "This 0x0100 case is for input.
|
||||
// This is the case where the Xbox wants to read input data from the controller.
|
||||
// Confirmed with a real Duke controller :
|
||||
// If the buffer provided by the Xbox is too small, the controller will cut the transfer when the buffer is full (actual_length is patched).
|
||||
// If the buffer is too large the controller will STALL instead.
|
||||
// If the buffer has the correct length the full input data is transferred."
|
||||
if (value == 0x0100) {
|
||||
if (length <= m_XidState->in_state.bLength) {
|
||||
// TODO: implement input devices
|
||||
//SDL2Devices* controller = g_InputDeviceManager->FindDeviceFromXboxPort(m_Port);
|
||||
//if (controller != nullptr) {
|
||||
// controller->ReadButtonState(&m_XidState->in_state.wButtons, m_XidState->in_state.bAnalogButtons,
|
||||
// &m_XidState->in_state.sThumbLX, &m_XidState->in_state.sThumbLY, &m_XidState->in_state.sThumbRX,
|
||||
// &m_XidState->in_state.sThumbRY);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// // ergo720: this shouldn't really happen. If it does, it either means that m_Port is wrong or there's a bug
|
||||
// // in the InputDeviceManager
|
||||
// p->Status = USB_RET_STALL;
|
||||
// assert(0);
|
||||
//}
|
||||
std::memcpy(data, &m_XidState->in_state, m_XidState->in_state.bLength);
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
p->Status = USB_RET_STALL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -334,18 +371,27 @@ void XidGamepad::UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
|||
// request is the same as for the Get_Report request, however the data direction is reversed and the Report
|
||||
// Data is sent from host to device."
|
||||
log_debug("XID: Gamepad SET_REPORT 0x%X", value);
|
||||
if (value == 0x200) {
|
||||
// Read length, then the entire packet
|
||||
std::memcpy(&m_XidState->out_state, data, sizeof(m_XidState->out_state));
|
||||
assert(m_XidState->out_state.length == sizeof(m_XidState->out_state));
|
||||
assert(m_XidState->out_state.length <= length);
|
||||
//FIXME: Check actuator endianess
|
||||
log_debug("XID: Set rumble power to left: 0x%X and right: 0x%X",
|
||||
m_XidState->out_state.left_actuator_strength,
|
||||
m_XidState->out_state.right_actuator_strength);
|
||||
p->ActualLength = m_XidState->out_state.length;
|
||||
// JayFoxRox's analysis: "The 0x0200 case below is for output.
|
||||
// This is the case where the Xbox wants to write rumble data to the controller.
|
||||
// To my knowledge :
|
||||
// If the buffer provided by the Xbox is too small the transfer will STALL.
|
||||
// If the buffer is too large the transfer will STALL.
|
||||
// If the buffer has the correct length the full output data is transferred."
|
||||
if (value == 0x0200) {
|
||||
if (length == m_XidState->out_state.length) {
|
||||
// Read length, then the entire packet
|
||||
std::memcpy(&m_XidState->out_state, data, sizeof(m_XidState->out_state));
|
||||
/* FIXME: This should also be a STALL */
|
||||
assert(m_XidState->out_state.length == sizeof(m_XidState->out_state));
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
}
|
||||
UpdateForceFeedback();
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
@ -361,6 +407,7 @@ void XidGamepad::UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
|||
p->ActualLength = m_XidState->xid_desc->bLength;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
|
@ -369,9 +416,24 @@ void XidGamepad::UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
|||
case VendorInterfaceRequest | XID_GET_CAPABILITIES:
|
||||
{
|
||||
log_debug("XID: Gamepad XID_GET_CAPABILITIES 0x%x", value);
|
||||
/* FIXME: ! */
|
||||
p->Status = USB_RET_STALL;
|
||||
//assert(false);
|
||||
if (value == 0x0100) {
|
||||
if (length > m_XidState->in_state_capabilities.bLength) {
|
||||
length = m_XidState->in_state_capabilities.bLength;
|
||||
}
|
||||
std::memcpy(data, &m_XidState->in_state_capabilities, length);
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else if (value == 0x0200) {
|
||||
if (length > m_XidState->out_state_capabilities.length) {
|
||||
length = m_XidState->out_state_capabilities.length;
|
||||
}
|
||||
std::memcpy(data, &m_XidState->out_state_capabilities, length);
|
||||
p->ActualLength = length;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -408,13 +470,24 @@ void XidGamepad::UsbXid_HandleData(XboxDeviceState* dev, USBPacket* p) {
|
|||
case USB_TOKEN_IN:
|
||||
{
|
||||
if (p->Endpoint->Num == 2) {
|
||||
if (m_XidState->in_dirty) {
|
||||
m_UsbDev->USB_PacketCopy(p, &m_XidState->in_state, m_XidState->in_state.bLength);
|
||||
m_XidState->in_dirty = false;
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_NAK;
|
||||
}
|
||||
//SDL2Devices* controller = g_InputDeviceManager->FindDeviceFromXboxPort(m_Port);
|
||||
//if (controller != nullptr) {
|
||||
// bool ret;
|
||||
// ret = controller->ReadButtonState(&m_XidState->in_state.wButtons, m_XidState->in_state.bAnalogButtons,
|
||||
// &m_XidState->in_state.sThumbLX, &m_XidState->in_state.sThumbLY, &m_XidState->in_state.sThumbRX,
|
||||
// &m_XidState->in_state.sThumbRY);
|
||||
// if (ret) {
|
||||
// m_UsbDev->USB_PacketCopy(p, &m_XidState->in_state, m_XidState->in_state.bLength);
|
||||
// }
|
||||
// else {
|
||||
p->Status = USB_RET_NAK;
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// p->Status = USB_RET_STALL;
|
||||
// assert(0);
|
||||
//}
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
|
@ -424,7 +497,13 @@ void XidGamepad::UsbXid_HandleData(XboxDeviceState* dev, USBPacket* p) {
|
|||
|
||||
case USB_TOKEN_OUT:
|
||||
{
|
||||
p->Status = USB_RET_STALL;
|
||||
if (p->Endpoint->Num == 2) {
|
||||
m_UsbDev->USB_PacketCopy(p, &m_XidState->out_state, m_XidState->out_state.length);
|
||||
UpdateForceFeedback();
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -442,4 +521,15 @@ void XidGamepad::XidCleanUp() {
|
|||
m_XidState = nullptr;
|
||||
}
|
||||
|
||||
void XidGamepad::UpdateForceFeedback() {
|
||||
// JayFoxRox's remarks: "Xbox -> XID packets were not tested
|
||||
// The handling of output packets / force feedback was not checked."
|
||||
// For the above reason we don't implement vibration support for now since the current
|
||||
// implementation is untested and could potentially contain errors
|
||||
/* FIXME: Check actuator endianess */
|
||||
log_debug("XID: Set rumble power to left: 0x%X and right: 0x%X\n",
|
||||
m_XidState->out_state.left_actuator_strength,
|
||||
m_XidState->out_state.right_actuator_strength);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -79,6 +79,9 @@ private:
|
|||
void UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
||||
int request, int value, int index, int length, uint8_t* data);
|
||||
void UsbXid_HandleData(XboxDeviceState* dev, USBPacket* p);
|
||||
// this should update the vibration strength of the real controller this gamepad represents.
|
||||
// It doesn't do anything at the moment
|
||||
void UpdateForceFeedback();
|
||||
};
|
||||
|
||||
extern XidGamepad* g_XidControllerObjArray[4];
|
||||
|
|
Loading…
Reference in a new issue