mirror of
https://github.com/StrikerX3/StrikeBox.git
synced 2024-06-23 14:53:22 -04:00
Sync code with ergo720's branch up to commit c18e2f6, except SDL stuff
SDL input (and other input sources, such as XInput) will be implemented as modules
This commit is contained in:
parent
e233726f9e
commit
c3dd820d31
|
@ -89,6 +89,10 @@ void ClockThread(TimerObject* Timer) {
|
|||
return;
|
||||
}
|
||||
Timer->Callback(Timer->Opaque);
|
||||
if (Timer->Exit.load()) {
|
||||
Timer_Destroy(Timer);
|
||||
return;
|
||||
}
|
||||
NewExpireTime = GetNextExpireTime(Timer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ file(GLOB DIR_HEADERS
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/pci/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/nv2a/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ohci/*.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xid/*.h
|
||||
)
|
||||
|
||||
file(GLOB DIR_SOURCES
|
||||
|
@ -15,6 +16,7 @@ file(GLOB DIR_SOURCES
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/sm/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/pci/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ohci/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xid/*.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
#include "ohci.h"
|
||||
#include "openxbox/log.h"
|
||||
|
||||
//#define DEBUG_PACKET
|
||||
//#define DEBUG_ISOCH
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
|
||||
|
@ -76,6 +79,8 @@ namespace openxbox {
|
|||
// HcFmRemaining
|
||||
#define OHCI_FMR_FR 0x00003FFF // FrameRemaining
|
||||
#define OHCI_FMR_FRT 0x80000000 // FrameRemainingToggle
|
||||
// LSThreshold
|
||||
#define OHCI_LS_THRESH 0x628 // LSThreshold
|
||||
// HcRhDescriptorA
|
||||
#define OHCI_RHA_RW_MASK 0x00000000 // Mask of supported features
|
||||
#define OHCI_RHA_PSM (1<<8) // PowerSwitchingMode
|
||||
|
@ -138,15 +143,15 @@ namespace openxbox {
|
|||
/* Bitfields for the first word of an Isochronous Transfer Desciptor. */
|
||||
/* CC & DI - same as in the General Transfer Desciptor */
|
||||
#define OHCI_TD_SF_SHIFT 0
|
||||
#define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT)
|
||||
#define OHCI_TD_SF_MASK (0xFFFF<<OHCI_TD_SF_SHIFT)
|
||||
#define OHCI_TD_FC_SHIFT 24
|
||||
#define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT)
|
||||
|
||||
/* Isochronous Transfer Desciptor - Offset / PacketStatusWord */
|
||||
#define OHCI_TD_PSW_CC_SHIFT 12
|
||||
#define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT)
|
||||
#define OHCI_TD_PSW_CC_MASK (0xF<<OHCI_TD_PSW_CC_SHIFT)
|
||||
#define OHCI_TD_PSW_SIZE_SHIFT 0
|
||||
#define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT)
|
||||
#define OHCI_TD_PSW_SIZE_MASK (0xFFF<<OHCI_TD_PSW_SIZE_SHIFT)
|
||||
|
||||
/* Mask the four least significant bits in an ED address */
|
||||
#define OHCI_DPTR_MASK 0xFFFFFFF0
|
||||
|
@ -193,6 +198,7 @@ OHCI::OHCI(Cpu* cpu, int Irq, USBPCIDevice* UsbObj)
|
|||
|
||||
m_IrqNum = Irq;
|
||||
m_UsbDevice = UsbObj;
|
||||
m_bFrameTime = false;
|
||||
ops = new USBPortOps();
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
@ -229,9 +235,13 @@ void OHCI::OHCI_FrameBoundaryWorker()
|
|||
{
|
||||
OHCI_HCCA hcca;
|
||||
|
||||
while (m_bFrameTime) {}
|
||||
m_bFrameTime = true;
|
||||
|
||||
if (OHCI_ReadHCCA(m_Registers.HcHCCA, &hcca)) {
|
||||
log_warning("OHCI: HCCA read error at physical address 0x%X\n", m_Registers.HcHCCA);
|
||||
OHCI_FatalError();
|
||||
m_bFrameTime = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -256,6 +266,7 @@ void OHCI::OHCI_FrameBoundaryWorker()
|
|||
|
||||
// Stop if UnrecoverableError happened or OHCI_SOF will crash
|
||||
if (m_Registers.HcInterruptStatus & OHCI_INTR_UE) {
|
||||
m_bFrameTime = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -301,6 +312,7 @@ void OHCI::OHCI_FrameBoundaryWorker()
|
|||
log_warning("OHCI: HCCA write error at physical address 0x%X\n", m_Registers.HcHCCA);
|
||||
OHCI_FatalError();
|
||||
}
|
||||
m_bFrameTime = false;
|
||||
}
|
||||
|
||||
void OHCI::OHCI_FatalError()
|
||||
|
@ -529,14 +541,14 @@ int OHCI::OHCI_ServiceEDlist(uint32_t Head, int Completion)
|
|||
|
||||
while ((ed.HeadP & OHCI_DPTR_MASK) != ed.TailP) { // a TD is available to be processed
|
||||
#ifdef DEBUG_PACKET
|
||||
DPRINTF("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u "
|
||||
"h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", cur,
|
||||
OHCI_BM(ed.flags, ED_FA), OHCI_BM(ed.flags, ED_EN),
|
||||
OHCI_BM(ed.flags, ED_D), (ed.flags & OHCI_ED_S) != 0,
|
||||
(ed.flags & OHCI_ED_K) != 0, (ed.flags & OHCI_ED_F) != 0,
|
||||
OHCI_BM(ed.flags, ED_MPS), (ed.head & OHCI_ED_H) != 0,
|
||||
(ed.head & OHCI_ED_C) != 0, ed.head & OHCI_DPTR_MASK,
|
||||
ed.tail & OHCI_DPTR_MASK, ed.next & OHCI_DPTR_MASK);
|
||||
log_spew("OHCI: ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u "
|
||||
"h=%u c=%u\n head=0x%.8x tailp=0x%.8x next=0x%.8x\n", current,
|
||||
OHCI_BM(ed.Flags, ED_FA), OHCI_BM(ed.Flags, ED_EN),
|
||||
OHCI_BM(ed.Flags, ED_D), (ed.Flags & OHCI_ED_S) != 0,
|
||||
(ed.Flags & OHCI_ED_K) != 0, (ed.Flags & OHCI_ED_F) != 0,
|
||||
OHCI_BM(ed.Flags, ED_MPS), (ed.HeadP & OHCI_ED_H) != 0,
|
||||
(ed.HeadP & OHCI_ED_C) != 0, ed.HeadP & OHCI_DPTR_MASK,
|
||||
ed.TailP & OHCI_DPTR_MASK, ed.NextED & OHCI_DPTR_MASK);
|
||||
#endif
|
||||
active = 1;
|
||||
|
||||
|
@ -548,8 +560,9 @@ int OHCI::OHCI_ServiceEDlist(uint32_t Head, int Completion)
|
|||
}
|
||||
else {
|
||||
// Handle isochronous endpoints
|
||||
if (OHCI_ServiceIsoTD(&ed, Completion))
|
||||
break;
|
||||
if (OHCI_ServiceIsoTD(&ed, Completion)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -568,7 +581,7 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
int direction;
|
||||
size_t length = 0, packetlen = 0;
|
||||
#ifdef DEBUG_PACKET
|
||||
const char *str = NULL;
|
||||
const char *str = nullptr;
|
||||
#endif
|
||||
int pid;
|
||||
int ret;
|
||||
|
@ -585,8 +598,7 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
completion = (addr == m_AsyncTD);
|
||||
if (completion && !m_AsyncComplete) { // ??
|
||||
#ifdef DEBUG_PACKET
|
||||
DPRINTF("Skipping async TD\n");
|
||||
log_debug("Skipping async TD\n");
|
||||
log_spew("OHCI: Skipping async TD\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
@ -671,17 +683,19 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
|
||||
flag_r = (td.Flags & OHCI_TD_R) != 0;
|
||||
#ifdef DEBUG_PACKET
|
||||
DPRINTF(" TD @ 0x%.8x %" PRId64 " of %" PRId64
|
||||
" bytes %s r=%d cbp=0x%.8x be=0x%.8x\n",
|
||||
addr, (int64_t)pktlen, (int64_t)len, str, flag_r, td.cbp, td.be);
|
||||
log_spew("OHCI: TD @ 0x%.8X %lld of %lld bytes %s r=%d cbp=0x%.8X be=0x%.8X\n",
|
||||
addr, (int64_t)packetlen, (int64_t)length, str, flag_r, td.CurrentBufferPointer, td.BufferEnd);
|
||||
|
||||
if (pktlen > 0 && dir != OHCI_TD_DIR_IN) {
|
||||
DPRINTF(" data:");
|
||||
for (i = 0; i < pktlen; i++) {
|
||||
printf(" %.2x", ohci->usb_buf[i]);
|
||||
#if LOG_LEVEL >= LOG_LEVEL_SPEW
|
||||
if (packetlen > 0 && direction != OHCI_TD_DIR_IN) {
|
||||
printf(" data:");
|
||||
for (i = 0; i < packetlen; i++) {
|
||||
printf(" %.2x", m_UsbBuffer[i]);
|
||||
}
|
||||
DPRINTF("\n");
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
if (completion) {
|
||||
m_AsyncTD = 0;
|
||||
|
@ -692,9 +706,6 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
// From XQEMU: "??? The hardware should allow one active packet per endpoint.
|
||||
// We only allow one active packet per controller. This should be sufficient
|
||||
// as long as devices respond in a timely manner."
|
||||
#ifdef DEBUG_PACKET
|
||||
DPRINTF("Too many pending packets\n");
|
||||
#endif
|
||||
log_debug("OHCI: too many pending packets\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -704,7 +715,7 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
m_UsbDevice->USB_PacketAddBuffer(&m_UsbPacket, m_UsbBuffer, packetlen);
|
||||
m_UsbDevice->USB_HandlePacket(dev, &m_UsbPacket);
|
||||
#ifdef DEBUG_PACKET
|
||||
DPRINTF("status=%d\n", ohci->usb_packet.status);
|
||||
log_spew("OHCI: status=%d\n", m_UsbPacket.Status);
|
||||
#endif
|
||||
if (m_UsbPacket.Status == USB_RET_ASYNC) {
|
||||
m_UsbDevice->USB_DeviceFlushEPqueue(dev, ep);
|
||||
|
@ -725,10 +736,12 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
OHCI_FatalError();
|
||||
}
|
||||
#ifdef DEBUG_PACKET
|
||||
DPRINTF(" data:");
|
||||
#if LOG_LEVEL >= LOG_LEVEL_SPEW
|
||||
printf(" data:");
|
||||
for (i = 0; i < ret; i++)
|
||||
printf(" %.2x", ohci->usb_buf[i]);
|
||||
DPRINTF("\n");
|
||||
printf(" %.2x", m_UsbBuffer[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
|
@ -869,9 +882,11 @@ void OHCI::OHCI_StateReset()
|
|||
m_Registers.HcFmRemaining = 0;
|
||||
m_Registers.HcFmNumber = 0;
|
||||
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.HcRhDescriptorB = 0; // The attached devices are removable and use PowerSwitchingMode to control the power on the ports
|
||||
m_Registers.HcRhStatus = 0;
|
||||
|
||||
m_DoneCount = 7;
|
||||
|
||||
|
@ -1379,7 +1394,7 @@ int OHCI::OHCI_PortSetIfConnected(int i, uint32_t Value)
|
|||
if (!(m_Registers.RhPort[i].HcRhPortStatus & OHCI_PORT_CCS)) {
|
||||
m_Registers.RhPort[i].HcRhPortStatus |= OHCI_PORT_CSC;
|
||||
if (m_Registers.HcRhStatus & OHCI_RHS_DRWE) {
|
||||
// TODO: CSC is a wakeup event
|
||||
// from XQEMU: TODO: CSC is a wakeup event
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1476,7 +1491,7 @@ void OHCI::OHCI_Wakeup(USBPort* port1) {
|
|||
|
||||
void OHCI::OHCI_AsyncCompletePacket(USBPort* port, USBPacket* packet) {
|
||||
#ifdef DEBUG_PACKET
|
||||
log_debug("Async packet complete");
|
||||
log_spew("OHCI: Async packet complete");
|
||||
#endif
|
||||
m_AsyncComplete = 1;
|
||||
OHCI_ProcessLists(1);
|
||||
|
@ -1521,7 +1536,7 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
|
|||
int dir;
|
||||
size_t len = 0;
|
||||
#ifdef DEBUG_ISOCH
|
||||
const char *str = NULL;
|
||||
const char *str = nullptr;
|
||||
#endif
|
||||
int pid;
|
||||
int ret;
|
||||
|
@ -1551,20 +1566,20 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
|
|||
relative_frame_number = USUB(m_Registers.HcFmNumber & 0xFFFF, starting_frame);
|
||||
|
||||
#ifdef DEBUG_ISOCH
|
||||
log_spew("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"
|
||||
log_spew("OHCI: --- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"
|
||||
"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
|
||||
"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
|
||||
"0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
|
||||
"frame_number 0x%.8x starting_frame 0x%.8x\n"
|
||||
"frame_count 0x%.8x relative %d\n"
|
||||
"di 0x%.8x cc 0x%.8x\n",
|
||||
ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,
|
||||
iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,
|
||||
iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3],
|
||||
iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7],
|
||||
ohci->frame_number, starting_frame,
|
||||
ed->HeadP & OHCI_DPTR_MASK, ed->TailP & OHCI_DPTR_MASK,
|
||||
iso_td.Flags, iso_td.BufferPage0, iso_td.NextTD, iso_td.BufferEnd,
|
||||
iso_td.Offset[0], iso_td.Offset[1], iso_td.Offset[2], iso_td.Offset[3],
|
||||
iso_td.Offset[4], iso_td.Offset[5], iso_td.Offset[6], iso_td.Offset[7],
|
||||
m_Registers.HcFmNumber, starting_frame,
|
||||
frame_count, relative_frame_number,
|
||||
OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC));
|
||||
OHCI_BM(iso_td.Flags, TD_DI), OHCI_BM(iso_td.Flags, TD_CC));
|
||||
#endif
|
||||
|
||||
if (relative_frame_number < 0) {
|
||||
|
@ -1717,7 +1732,7 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
|
|||
}
|
||||
|
||||
#ifdef DEBUG_ISOCH
|
||||
printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",
|
||||
log_spew("OHCI: so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",
|
||||
start_offset, end_offset, start_addr, end_addr, str, len, ret);
|
||||
#endif
|
||||
|
||||
|
@ -1790,9 +1805,4 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void OHCI::OHCI_AssignUsbPortStruct(int port, XboxDeviceState* dev) {
|
||||
dev->Port = &m_Registers.RhPort[port].UsbPort;
|
||||
m_Registers.RhPort[port].UsbPort.Dev = dev;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,16 +46,6 @@
|
|||
|
||||
namespace openxbox {
|
||||
|
||||
#define USB_RET_SUCCESS (0)
|
||||
#define USB_RET_NODEV (-1)
|
||||
#define USB_RET_NAK (-2)
|
||||
#define USB_RET_STALL (-3)
|
||||
#define USB_RET_BABBLE (-4)
|
||||
#define USB_RET_IOERROR (-5)
|
||||
#define USB_RET_ASYNC (-6)
|
||||
#define USB_RET_ADD_TO_QUEUE (-7)
|
||||
#define USB_RET_REMOVE_FROM_QUEUE (-8)
|
||||
|
||||
|
||||
// Abbreviations used:
|
||||
// OHCI: Open Host Controller Interface; the standard used on the Xbox to comunicate with the usb devices
|
||||
|
@ -151,6 +141,10 @@ struct OHCI_Registers {
|
|||
/* OHCI class representing the state of the HC */
|
||||
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
|
||||
std::atomic_bool m_bFrameTime;
|
||||
|
||||
// constructor
|
||||
OHCI(Cpu* cpu, int Irqn, USBPCIDevice* UsbObj);
|
||||
// destructor
|
||||
|
@ -159,8 +153,6 @@ public:
|
|||
uint32_t OHCI_ReadRegister(uint32_t Addr);
|
||||
// write a register
|
||||
void OHCI_WriteRegister(uint32_t Addr, uint32_t Value);
|
||||
// update the USBPort struct with the device attached
|
||||
void OHCI_AssignUsbPortStruct(int port, XboxDeviceState* dev);
|
||||
|
||||
private:
|
||||
Cpu* m_cpu;
|
||||
|
@ -215,7 +207,7 @@ private:
|
|||
void OHCI_SetInterrupt(uint32_t Value);
|
||||
// calculate frame time remaining
|
||||
uint32_t OHCI_GetFrameRemaining();
|
||||
//
|
||||
// halt the endpoints of the device
|
||||
void OHCI_StopEndpoints();
|
||||
// set root hub status
|
||||
void OHCI_SetHubStatus(uint32_t Value);
|
||||
|
|
|
@ -127,6 +127,16 @@ namespace openxbox {
|
|||
#define USB_DT_INTERFACE 0x04
|
||||
#define USB_DT_ENDPOINT 0x05
|
||||
|
||||
#define USB_RET_SUCCESS (0)
|
||||
#define USB_RET_NODEV (-1)
|
||||
#define USB_RET_NAK (-2)
|
||||
#define USB_RET_STALL (-3)
|
||||
#define USB_RET_BABBLE (-4)
|
||||
#define USB_RET_IOERROR (-5)
|
||||
#define USB_RET_ASYNC (-6)
|
||||
#define USB_RET_ADD_TO_QUEUE (-7)
|
||||
#define USB_RET_REMOVE_FROM_QUEUE (-8)
|
||||
|
||||
typedef enum _USB_SPEED {
|
||||
USB_SPEED_MASK_LOW = 1 << 0,
|
||||
USB_SPEED_MASK_FULL = 1 << 1,
|
||||
|
@ -143,6 +153,13 @@ typedef enum USBPacketState {
|
|||
}
|
||||
USBPacketState;
|
||||
|
||||
/* same as Linux kernel root hubs */
|
||||
typedef enum {
|
||||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT,
|
||||
STR_SERIALNUMBER,
|
||||
};
|
||||
|
||||
struct USBPacket;
|
||||
struct USBPort;
|
||||
struct USBDeviceClass;
|
||||
|
@ -190,7 +207,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(bool bDefault);
|
||||
USBDescIface();
|
||||
~USBDescIface();
|
||||
};
|
||||
|
||||
|
@ -222,7 +239,7 @@ 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(bool bDefault);
|
||||
USBDescDevice();
|
||||
~USBDescDevice();
|
||||
};
|
||||
|
||||
|
@ -241,7 +258,7 @@ 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(bool bDefault);
|
||||
USBDesc();
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
|
@ -319,7 +336,6 @@ struct USBEndpoint {
|
|||
struct XboxDeviceState {
|
||||
USBPort* Port; // usb port struct of this device
|
||||
int PortPath; // port index to which this device is attached to
|
||||
char* Serial;
|
||||
uint32_t flags;
|
||||
USBDeviceClass* klass; // usb class struct of this device
|
||||
|
||||
|
@ -333,7 +349,7 @@ struct XboxDeviceState {
|
|||
uint8_t SetupBuffer[8]; // setup packet buffer - 8 bytes (control transfers only)
|
||||
uint8_t DataBuffer[4096]; // buffer where to write the data requested during usb requests
|
||||
int32_t RemoteWakeup; // wakeup flag
|
||||
int32_t SetupState; // result of a setup tken processing operation
|
||||
int32_t 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?
|
||||
|
||||
|
@ -399,7 +415,7 @@ struct USBPort {
|
|||
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
|
||||
std::string Path; // the number of the port + 1, used to create a serial number for this device
|
||||
int PortIndex; // internal port index
|
||||
};
|
||||
|
||||
|
@ -415,7 +431,7 @@ struct USBDeviceClass {
|
|||
std::function<void(XboxDeviceState* dev, USBPacket* p)> cancel_packet;
|
||||
|
||||
// Called when device is destroyed.
|
||||
std::function<void(XboxDeviceState* dev)> handle_destroy;
|
||||
std::function<void(void)> handle_destroy;
|
||||
|
||||
// Attach the device
|
||||
std::function<void(XboxDeviceState* dev)> handle_attach;
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include "openxbox/log.h"
|
||||
|
||||
|
@ -47,109 +47,92 @@
|
|||
|
||||
namespace openxbox {
|
||||
|
||||
// This array is used to translate an xbox player to the corresponding usb port
|
||||
// The port associations are taken from XQEMU
|
||||
int PlayerToUsbArray[] = {
|
||||
-1,
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
2,
|
||||
};
|
||||
Hub* g_HubObjArray[4] = { nullptr };
|
||||
|
||||
USBDescIface::USBDescIface(bool bDefault) {
|
||||
USBDescIface::USBDescIface() {
|
||||
std::memset(this, 0, sizeof(USBDescIface));
|
||||
if (bDefault) {
|
||||
descs = new USBDescOther();
|
||||
eps = new USBDescEndpoint();
|
||||
bInterfaceNumber = 0;
|
||||
bNumEndpoints = 1;
|
||||
bInterfaceClass = USB_CLASS_HUB;
|
||||
eps = new USBDescEndpoint();
|
||||
eps->bEndpointAddress = USB_DIR_IN | 0x01;
|
||||
eps->bmAttributes = USB_ENDPOINT_XFER_INT;
|
||||
eps->wMaxPacketSize = 1 + (NUM_PORTS + 7) / 8;
|
||||
eps->bInterval = 0xFF;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
USBDescIface::~USBDescIface() {
|
||||
delete descs;
|
||||
if (bNumEndpoints != 1) {
|
||||
delete[] eps;
|
||||
return;
|
||||
}
|
||||
delete eps;
|
||||
}
|
||||
|
||||
static const USBDescIface desc_iface_hub(true);
|
||||
static const USBDescIface desc_iface_hub;
|
||||
|
||||
USBDescDevice::USBDescDevice(bool bDefault) {
|
||||
USBDescDevice::USBDescDevice() {
|
||||
std::memset(this, 0, sizeof(USBDescDevice));
|
||||
if (bDefault) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
USBDescDevice::~USBDescDevice() {
|
||||
delete confs;
|
||||
if (bNumConfigurations != 1) {
|
||||
delete[] confs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const USBDescDevice desc_device_hub(true);
|
||||
static const USBDescDevice desc_device_hub;
|
||||
|
||||
USBDesc::USBDesc(bool bDefault) {
|
||||
USBDesc::USBDesc() {
|
||||
std::memset(this, 0, sizeof(USBDesc));
|
||||
if (bDefault) {
|
||||
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;
|
||||
}
|
||||
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(true);
|
||||
static const USBDesc desc_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
|
||||
// because then this descriptor will be retrieved during a standard GetDescriptor request instead of the hub-specific GetHubDescriptor request
|
||||
static const uint8_t HubDescriptor[] = {
|
||||
0x0A, // u8 bDescLength; 10 bytes
|
||||
0x29, // u8 bDescriptorType; Hub-descriptor
|
||||
NUM_PORTS, // u8 bNbrPorts; 0x08
|
||||
0x0a, // u16 wHubCharacteristics; (individual port over-current protection, no power switching)
|
||||
0x00,
|
||||
0x01, // u8 bPwrOn2pwrGood; 2 ms
|
||||
0x00, // u8 bHubContrCurrent; 0 mA
|
||||
0x00, // u16 DeviceRemovable; all devices are removable
|
||||
0x00,
|
||||
0xFF, // u8 PortPwrCtrlMask; all 1's for compatibility reasons
|
||||
};
|
||||
|
||||
int Hub::Init(int port) {
|
||||
if (port > 4 || port < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Hub::Init(int pport) {
|
||||
XboxDeviceState* dev = ClassInitFn();
|
||||
int rc = UsbHubClaimPort(dev, port);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_EpInit(dev);
|
||||
int rc = UsbHubClaimPort(dev, pport);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
rc = m_UsbDev->USB_DeviceInit(dev);
|
||||
if (rc != 0) {
|
||||
UsbHubReleasePort(dev);
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_DeviceInit(dev);
|
||||
m_UsbDev->USB_DeviceAttach(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Hub::~Hub() {
|
||||
delete m_pPeripheralFuncStruct;
|
||||
delete m_HubState->ports[0].port.Operations;
|
||||
delete m_HubState;
|
||||
m_pPeripheralFuncStruct = nullptr;
|
||||
m_HubState = nullptr;
|
||||
}
|
||||
|
||||
XboxDeviceState* Hub::ClassInitFn() {
|
||||
m_pPeripheralFuncStruct = new USBDeviceClass();
|
||||
m_HubState = new USBHubState();
|
||||
|
@ -167,7 +150,7 @@ XboxDeviceState* Hub::ClassInitFn() {
|
|||
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->handle_destroy = std::bind(&Hub::UsbHub_HandleDestroy, this);
|
||||
m_pPeripheralFuncStruct->product_desc = dev->ProductDesc.c_str();
|
||||
m_pPeripheralFuncStruct->usb_desc = &desc_hub;
|
||||
}
|
||||
|
@ -175,23 +158,35 @@ XboxDeviceState* Hub::ClassInitFn() {
|
|||
return dev;
|
||||
}
|
||||
|
||||
int Hub::UsbHubClaimPort(XboxDeviceState* dev, int pport) {
|
||||
int usb_port;
|
||||
int Hub::UsbHubClaimPort(XboxDeviceState* dev, int port) {
|
||||
int i;
|
||||
std::vector<USBPort*>::iterator it;
|
||||
|
||||
assert(dev->Port == nullptr);
|
||||
|
||||
if (pport > 4 || pport < 1) { return -1; };
|
||||
|
||||
usb_port = PlayerToUsbArray[pport];
|
||||
if (usb_port > 2) {
|
||||
if (port > 2) {
|
||||
m_UsbDev = g_USB0; // FIXME: how to retrieve these?
|
||||
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 3, dev);
|
||||
}
|
||||
else {
|
||||
m_UsbDev = g_USB1; // FIXME: how to retrieve these?
|
||||
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 1, dev);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for (auto usb_port : m_UsbDev->m_FreePorts) {
|
||||
if (usb_port->Path == std::to_string(port)) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i == 2) {
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -209,14 +204,9 @@ int Hub::UsbHub_Initfn(XboxDeviceState* dev) {
|
|||
USBPortOps* ops;
|
||||
int i;
|
||||
|
||||
if (dev->Port->HubCount == 5) {
|
||||
log_debug("Hub: chain too deep");
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_UsbDev->USB_CreateSerial(dev, "314159");
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_MANUFACTURER, "Cxbx-Reloaded");
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_PRODUCT, "Cxbx-Reloaded USB Hub");
|
||||
m_UsbDev->USB_CreateSerial(dev, std::string("314159"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_MANUFACTURER, std::string("Cxbx-Reloaded"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_PRODUCT, std::string("Cxbx-Reloaded USB Hub"));
|
||||
m_UsbDev->USBDesc_Init(dev);
|
||||
m_HubState->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 1);
|
||||
|
||||
|
@ -274,7 +264,6 @@ void Hub::UsbHub_HandleReset() {
|
|||
}
|
||||
}
|
||||
void Hub::UsbHub_HandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) {
|
||||
USBHubState * s = (USBHubState *)dev;
|
||||
int ret;
|
||||
ret = m_UsbDev->USBDesc_HandleControl(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
|
@ -283,101 +272,242 @@ void Hub::UsbHub_HandleControl(XboxDeviceState* dev, USBPacket* p, int request,
|
|||
|
||||
switch (request) {
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == 0 && index != 0x81) { /* clear ep halt */
|
||||
{
|
||||
// clear ep halt and bEndpointAddress of hub is 0x81
|
||||
if (value == 0 && index != 0x81) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
/* usb specific requests */
|
||||
}
|
||||
|
||||
case GetHubStatus:
|
||||
{
|
||||
// From the standard: "This request returns the current hub status and the states that have changed since the previous acknowledgment.
|
||||
// The first word of data contains wHubStatus. The second word of data contains wHubChange"
|
||||
// We always report that the local power supply is good and that currently there is no over-power condition
|
||||
data[0] = 0;
|
||||
data[1] = 0;
|
||||
data[2] = 0;
|
||||
data[3] = 0;
|
||||
p->actual_length = 4;
|
||||
p->ActualLength = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case GetPortStatus:
|
||||
{
|
||||
// From the standard: "This request returns the current port status and the current value of the port status change bits.
|
||||
// The first word of data contains wPortStatus. The second word of data contains wPortChange"
|
||||
unsigned int n = index - 1;
|
||||
USBHubPort * port;
|
||||
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);
|
||||
port = &m_HubState->ports[n];
|
||||
log_debug("OHCI Hub: %s GetPortStatus -> Address 0x%X, wIndex %d, wPortStatus %d, wPortChange %d",
|
||||
__func__, m_HubState->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;
|
||||
p->ActualLength = 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SetHubFeature:
|
||||
case ClearHubFeature:
|
||||
{
|
||||
if (value != 0 && value != 1) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SetPortFeature:
|
||||
{
|
||||
// From the standard: "This request sets a value reported in the port status. Features that can be set with this request are PORT_RESET,
|
||||
// PORT_SUSPEND and PORT_POWER; others features are not required to be set by this request"
|
||||
unsigned int n = index - 1;
|
||||
USBHubPort * port;
|
||||
USBDevice * dev;
|
||||
trace_usb_hub_set_port_feature(s->dev.addr, index, feature_name(value));
|
||||
USBHubPort* port;
|
||||
XboxDeviceState* dev;
|
||||
|
||||
log_debug("OHCI Hub: %s SetPortFeature -> Address 0x%X, wIndex %d, Feature %s",
|
||||
__func__, m_HubState->dev.Addr, index, GetFeatureName(value));
|
||||
|
||||
if (n >= NUM_PORTS) {
|
||||
goto fail;
|
||||
}
|
||||
port = &s->ports[n];
|
||||
dev = port->port.dev;
|
||||
port = &m_HubState->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);
|
||||
{
|
||||
if (dev && dev->Attached) {
|
||||
m_UsbDev->USB_DeviceReset(dev);
|
||||
port->wPortChange |= PORT_STAT_C_RESET;
|
||||
/* set enable bit */
|
||||
port->wPortStatus |= PORT_STAT_ENABLE;
|
||||
usb_wakeup(s->intr, 0);
|
||||
m_UsbDev->USB_Wakeup(m_HubState->intr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_POWER:
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ClearPortFeature:
|
||||
{
|
||||
// From the standard: "This request resets a value reported in the port status"
|
||||
unsigned int n = index - 1;
|
||||
USBHubPort *port;
|
||||
|
||||
log_debug("OHCI Hub: %s ClearPortFeature -> Address 0x%X, wIndex %d, Feature %s",
|
||||
__func__, m_HubState->dev.Addr, index, GetFeatureName(value));
|
||||
|
||||
if (n >= NUM_PORTS) {
|
||||
goto fail;
|
||||
}
|
||||
port = &m_HubState->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;
|
||||
std::memcpy(data, HubDescriptor, sizeof(HubDescriptor));
|
||||
p->ActualLength = sizeof(HubDescriptor);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fail:
|
||||
p->status = USB_RET_STALL;
|
||||
p->Status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hub::UsbHub_HandleData(XboxDeviceState* dev, USBPacket* p) {
|
||||
switch (p->Pid) {
|
||||
case USB_TOKEN_IN:
|
||||
{
|
||||
if (p->Endpoint->Num == 1) {
|
||||
USBHubPort* port;
|
||||
unsigned int status;
|
||||
uint8_t buf[4];
|
||||
int i, n;
|
||||
status = 0;
|
||||
for (i = 0; i < NUM_PORTS; i++) {
|
||||
port = &m_HubState->ports[i];
|
||||
if (port->wPortChange) {
|
||||
status |= (1 << (i + 1));
|
||||
}
|
||||
}
|
||||
if (status != 0) {
|
||||
n = (NUM_PORTS + 1 + 7) / 8;
|
||||
if (p->IoVec.Size == 1) { // FreeBSD workaround
|
||||
n = 1;
|
||||
}
|
||||
else if (n > p->IoVec.Size) {
|
||||
p->Status = USB_RET_BABBLE;
|
||||
return;
|
||||
}
|
||||
log_debug("OHCI Hub: %s Address 0x%X, Status %d", __func__, m_HubState->dev.Addr, status);
|
||||
for (i = 0; i < n; i++) {
|
||||
buf[i] = status >> (8 * i);
|
||||
}
|
||||
m_UsbDev->USB_PacketCopy(p, buf, n);
|
||||
}
|
||||
else {
|
||||
p->Status = USB_RET_NAK; // usb11 11.13.1
|
||||
}
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_TOKEN_OUT:
|
||||
default:
|
||||
fail:
|
||||
p->Status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Hub::UsbHub_HandleDestroy() {
|
||||
// Inform upstream that the hub is detached and gone
|
||||
m_UsbDev->USB_DeviceDetach(&m_HubState->dev);
|
||||
m_UsbDev->m_FreePorts.push_back(m_HubState->dev.Port);
|
||||
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
if (m_HubState->ports[i].port.Dev) {
|
||||
// Also destroy attached downstream device
|
||||
m_HubState->ports[i].port.Dev->klass->handle_destroy();
|
||||
}
|
||||
else {
|
||||
m_UsbDev->USB_UnregisterPort(&m_HubState->ports[i].port);
|
||||
}
|
||||
}
|
||||
UsbHubReleasePort(&m_HubState->dev);
|
||||
HubCleanUp();
|
||||
}
|
||||
|
||||
void Hub::UsbHub_Attach(USBPort* port1) {
|
||||
USBHubPort* port = &m_HubState->ports[port1->PortIndex];
|
||||
|
||||
|
@ -428,4 +558,103 @@ void Hub::UsbHub_Complete(USBPort* port, USBPacket* packet) {
|
|||
m_HubState->dev.Port->Operations->complete(m_HubState->dev.Port, packet);
|
||||
}
|
||||
|
||||
std::string Hub::GetFeatureName(int feature) {
|
||||
std::string str;
|
||||
|
||||
switch (feature) {
|
||||
case PORT_CONNECTION:
|
||||
{
|
||||
str = "connection";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_ENABLE:
|
||||
{
|
||||
str = "enable";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_SUSPEND:
|
||||
{
|
||||
str = "suspend";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_OVERCURRENT:
|
||||
{
|
||||
str = "overcurrent";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_RESET:
|
||||
{
|
||||
str = "reset";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_POWER:
|
||||
{
|
||||
str = "power";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_LOWSPEED:
|
||||
{
|
||||
str = "lowspeed";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_CONNECTION:
|
||||
{
|
||||
str = "change_connection";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_ENABLE:
|
||||
{
|
||||
str = "change_enable";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_SUSPEND:
|
||||
{
|
||||
str = "change_suspend";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_OVERCURRENT:
|
||||
{
|
||||
str = "change_overcurrent";
|
||||
break;
|
||||
}
|
||||
|
||||
case PORT_C_RESET:
|
||||
{
|
||||
str = "change_reset";
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
str = "?";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void Hub::HubCleanUp() {
|
||||
delete m_pPeripheralFuncStruct;
|
||||
delete m_HubState->ports[0].port.Operations;
|
||||
delete m_HubState;
|
||||
m_pPeripheralFuncStruct = nullptr;
|
||||
m_HubState = nullptr;
|
||||
}
|
||||
|
||||
void Hub::HubDestroy() {
|
||||
while (m_UsbDev->m_HostController->m_bFrameTime) {}
|
||||
m_UsbDev->m_HostController->m_bFrameTime = true;
|
||||
m_pPeripheralFuncStruct->handle_destroy();
|
||||
m_UsbDev->m_HostController->m_bFrameTime = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "ohci_common.h"
|
||||
#include "../pci/usb_pci.h"
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
|
@ -54,19 +54,32 @@ namespace openxbox {
|
|||
#define PORT_STAT_POWER 0x0100
|
||||
#define PORT_STAT_LOW_SPEED 0x0200
|
||||
|
||||
#define PORT_STAT_C_CONNECTION 0x0001
|
||||
#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_OVERCURRENT 0x0008
|
||||
#define PORT_STAT_C_RESET 0x0010
|
||||
|
||||
#define ClearHubFeature (0x2000 | USB_REQ_CLEAR_FEATURE)
|
||||
#define ClearPortFeature (0x2300 | USB_REQ_CLEAR_FEATURE)
|
||||
#define GetHubDescriptor (0xA000 | USB_REQ_GET_DESCRIPTOR)
|
||||
#define GetHubStatus (0xA000 | USB_REQ_GET_STATUS)
|
||||
#define GetPortStatus (0xA300 | USB_REQ_GET_STATUS)
|
||||
#define SetHubFeature (0x2000 | USB_REQ_SET_FEATURE)
|
||||
#define SetPortFeature (0x2300 | USB_REQ_SET_FEATURE)
|
||||
|
||||
/* same as Linux kernel root hubs */
|
||||
typedef enum {
|
||||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT,
|
||||
STR_SERIALNUMBER,
|
||||
};
|
||||
#define PORT_CONNECTION 0
|
||||
#define PORT_ENABLE 1
|
||||
#define PORT_SUSPEND 2
|
||||
#define PORT_OVERCURRENT 3
|
||||
#define PORT_RESET 4
|
||||
#define PORT_POWER 8
|
||||
#define PORT_LOWSPEED 9
|
||||
#define PORT_C_CONNECTION 16
|
||||
#define PORT_C_ENABLE 17
|
||||
#define PORT_C_SUSPEND 18
|
||||
#define PORT_C_OVERCURRENT 19
|
||||
#define PORT_C_RESET 20
|
||||
|
||||
struct USBHubPort {
|
||||
USBPort port; // downstream port status
|
||||
|
@ -83,15 +96,16 @@ struct USBHubState {
|
|||
/* Class which implements a usb hub */
|
||||
class Hub {
|
||||
public:
|
||||
// initialize this peripheral
|
||||
int Init(int pport);
|
||||
// destructor
|
||||
~Hub();
|
||||
// usb device this hub is attached to
|
||||
USBPCIDevice* m_UsbDev = nullptr;
|
||||
|
||||
// initialize this hub
|
||||
int Init(int port);
|
||||
// start hub destruction
|
||||
void HubDestroy();
|
||||
|
||||
|
||||
private:
|
||||
// usb device this hub is attached to
|
||||
USBPCIDevice* m_UsbDev = nullptr;
|
||||
// hub state
|
||||
USBHubState* m_HubState = nullptr;
|
||||
// hub class functions
|
||||
|
@ -106,7 +120,7 @@ private:
|
|||
void UsbHub_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
||||
int request, int value, int index, int length, uint8_t* data);
|
||||
void UsbHub_HandleData(XboxDeviceState* dev, USBPacket* p);
|
||||
void UsbHub_HandleDestroy(XboxDeviceState* dev);
|
||||
void UsbHub_HandleDestroy();
|
||||
// see USBPortOps struct for info
|
||||
void UsbHub_Attach(USBPort* port1);
|
||||
void UsbHub_Detach(USBPort* port1);
|
||||
|
@ -117,6 +131,10 @@ private:
|
|||
int UsbHubClaimPort(XboxDeviceState* dev, int port);
|
||||
// free the usb port used by this hub
|
||||
void UsbHubReleasePort(XboxDeviceState* dev);
|
||||
// retieve the name of the feature of the usb request
|
||||
std::string GetFeatureName(int feature);
|
||||
// destroy hub resources
|
||||
void HubCleanUp();
|
||||
};
|
||||
|
||||
extern Hub* g_HubObjArray[4];
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "openxbox/log.h"
|
||||
|
@ -105,6 +105,13 @@ void USBPCIDevice::USB_RegisterPort(USBPort* Port, int Index, int SpeedMask, USB
|
|||
Port->SpeedMask = SpeedMask;
|
||||
Port->Operations = Ops;
|
||||
USB_PortLocation(Port, nullptr, Index + 1);
|
||||
m_FreePorts.push_back(Port);
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_UnregisterPort(USBPort* Port) {
|
||||
auto it = std::find(m_FreePorts.begin(), m_FreePorts.end(), Port);
|
||||
assert(it != m_FreePorts.end());
|
||||
m_FreePorts.erase(it);
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_PortReset(USBPort* Port) {
|
||||
|
@ -152,7 +159,7 @@ void USBPCIDevice::USB_DeviceReset(XboxDeviceState* dev) {
|
|||
dev->RemoteWakeup = 0;
|
||||
dev->Addr = 0;
|
||||
dev->State = USB_STATE_DEFAULT;
|
||||
usb_device_handle_reset(dev);
|
||||
USB_DeviceHandleReset(dev);
|
||||
}
|
||||
|
||||
XboxDeviceState* USBPCIDevice::USB_FindDevice(USBPort* Port, uint8_t Addr) {
|
||||
|
@ -232,8 +239,7 @@ void USBPCIDevice::USB_HandlePacket(XboxDeviceState* dev, USBPacket* p) {
|
|||
// hcd drivers cannot handle async for isoc
|
||||
assert(p->Endpoint->Type != USB_ENDPOINT_XFER_ISOC);
|
||||
// using async for interrupt packets breaks migration
|
||||
assert(p->Endpoint->Type != USB_ENDPOINT_XFER_INT ||
|
||||
(dev->flags & (1 << USB_DEV_FLAG_IS_HOST)));
|
||||
assert(p->Endpoint->Type != USB_ENDPOINT_XFER_INT);
|
||||
p->State = USB_PACKET_ASYNC;
|
||||
QTAILQ_INSERT_TAIL(&p->Endpoint->Queue, p, Queue);
|
||||
}
|
||||
|
@ -287,14 +293,20 @@ void USBPCIDevice::USB_ProcessOne(USBPacket* p) {
|
|||
}
|
||||
switch (p->Pid) {
|
||||
case USB_TOKEN_SETUP:
|
||||
{
|
||||
USB_DoTokenSetup(dev, p);
|
||||
break;
|
||||
}
|
||||
case USB_TOKEN_IN:
|
||||
{
|
||||
DoTokenIn(dev, p);
|
||||
break;
|
||||
}
|
||||
case USB_TOKEN_OUT:
|
||||
{
|
||||
DoTokenOut(dev, p);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
p->Status = USB_RET_STALL;
|
||||
}
|
||||
|
@ -451,10 +463,10 @@ void USBPCIDevice::DoTokenOut(XboxDeviceState* s, USBPacket* p) {
|
|||
case SETUP_STATE_ACK:
|
||||
if (s->SetupBuffer[0] & USB_DIR_IN) {
|
||||
s->SetupState = SETUP_STATE_IDLE;
|
||||
/* transfer OK */
|
||||
// transfer OK
|
||||
}
|
||||
else {
|
||||
/* ignore additional output */
|
||||
// ignore additional output
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -529,7 +541,7 @@ void USBPCIDevice::USB_DeviceCancelPacket(XboxDeviceState* dev, USBPacket* p) {
|
|||
void USBPCIDevice::USB_DeviceHandleDestroy(XboxDeviceState* dev) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->handle_destroy) {
|
||||
klass->handle_destroy(dev);
|
||||
klass->handle_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,7 +611,7 @@ void USBPCIDevice::USB_EPsetType(XboxDeviceState* dev, int pid, int ep, uint8_t
|
|||
uep->Type = type;
|
||||
}
|
||||
|
||||
uint8_t USBPCIDevice::USB_EPsetIfnum(XboxDeviceState* dev, int pid, int ep, uint8_t ifnum) {
|
||||
void USBPCIDevice::USB_EPsetIfnum(XboxDeviceState* dev, int pid, int ep, uint8_t ifnum) {
|
||||
USBEndpoint* uep = USB_GetEP(dev, pid, ep);
|
||||
uep->IfNum = ifnum;
|
||||
}
|
||||
|
@ -614,13 +626,10 @@ void USBPCIDevice::USB_EPsetMaxPacketSize(XboxDeviceState* dev, int pid, int ep,
|
|||
|
||||
void USBPCIDevice::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;
|
||||
downstream->Path = upstream->Path + '.' + std::to_string(portnr);
|
||||
}
|
||||
else {
|
||||
std::snprintf(downstream->Path, sizeof(downstream->Path), "%d", portnr);
|
||||
downstream->HubCount = 0;
|
||||
downstream->Path = std::to_string(portnr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -634,6 +643,16 @@ void USBPCIDevice::USB_DeviceAttach(XboxDeviceState* dev) {
|
|||
USB_Attach(port);
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceDetach(XboxDeviceState* dev) {
|
||||
USBPort* port = dev->Port;
|
||||
|
||||
assert(port != nullptr);
|
||||
assert(dev->Attached);
|
||||
|
||||
USB_Detach(port);
|
||||
dev->Attached--;
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_EpInit(XboxDeviceState* dev) {
|
||||
USB_EpReset(dev);
|
||||
QTAILQ_INIT(&dev->EP_ctl.Queue);
|
||||
|
@ -681,20 +700,17 @@ void USBPCIDevice::USB_EpReset(XboxDeviceState* dev) {
|
|||
* the pci address in most cases). Third the physical port path.
|
||||
* Results in serial numbers like this: "314159-0000:00:1d.7-3".
|
||||
*/
|
||||
void USBPCIDevice::USB_CreateSerial(XboxDeviceState* dev, const char* str) {
|
||||
void USBPCIDevice::USB_CreateSerial(XboxDeviceState* dev, std::string&& str) {
|
||||
const USBDesc* desc = USBDesc_GetUsbDeviceDesc(dev);
|
||||
int index = desc->id.iSerialNumber;
|
||||
USBDescString* s;
|
||||
char serial[64];
|
||||
char* path;
|
||||
int dst;
|
||||
std::string str2;
|
||||
|
||||
assert(index != 0 && str != nullptr);
|
||||
dst = std::snprintf(serial, sizeof(serial), "%s", str);
|
||||
dst += std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", m_PciPath);
|
||||
std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", dev->Port->Path);
|
||||
assert(index != 0 && str.empty() == false);
|
||||
str += '-';
|
||||
str += m_PciPath;
|
||||
str += ('-' + dev->Port->Path);
|
||||
|
||||
USBDesc_SetString(dev, index, serial);
|
||||
USBDesc_SetString(dev, index, std::move(str));
|
||||
}
|
||||
|
||||
const USBDesc* USBPCIDevice::USBDesc_GetUsbDeviceDesc(XboxDeviceState* dev) {
|
||||
|
@ -708,7 +724,7 @@ const USBDesc* USBPCIDevice::USBDesc_GetUsbDeviceDesc(XboxDeviceState* dev) {
|
|||
void USBPCIDevice::USBDesc_Init(XboxDeviceState* dev) {
|
||||
const USBDesc* desc = USBDesc_GetUsbDeviceDesc(dev);
|
||||
|
||||
assert(desc != NULL);
|
||||
assert(desc != nullptr);
|
||||
dev->Speed = USB_SPEED_FULL;
|
||||
dev->SpeedMask = 0;
|
||||
if (desc->full) {
|
||||
|
@ -720,7 +736,7 @@ void USBPCIDevice::USBDesc_Init(XboxDeviceState* dev) {
|
|||
void USBPCIDevice::USBDesc_SetDefaults(XboxDeviceState* dev) {
|
||||
const USBDesc *desc = USBDesc_GetUsbDeviceDesc(dev);
|
||||
|
||||
assert(desc != NULL);
|
||||
assert(desc != nullptr);
|
||||
switch (dev->Speed) {
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
|
@ -729,7 +745,7 @@ void USBPCIDevice::USBDesc_SetDefaults(XboxDeviceState* dev) {
|
|||
break;
|
||||
}
|
||||
default:
|
||||
log_warning("Unknown speed parameter %d set in %s", dev->ProductDesc.c_str());
|
||||
log_warning("USB: Unknown speed parameter %d set in %s", dev->ProductDesc.c_str());
|
||||
}
|
||||
USBDesc_SetConfig(dev, 0);
|
||||
}
|
||||
|
@ -843,7 +859,7 @@ int USBPCIDevice::USBDesc_HandleControl(XboxDeviceState* dev, USBPacket *p, int
|
|||
// From the standard: "This request sets the device address for all future device accesses.
|
||||
// The wValue field specifies the device address to use for all subsequent accesses"
|
||||
dev->Addr = value;
|
||||
log_debug("Address 0x%X set for device %s", dev->Addr, dev->ProductDesc.c_str());
|
||||
log_debug("USB: Address 0x%X set for device %s", dev->Addr, dev->ProductDesc.c_str());
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -872,7 +888,7 @@ int USBPCIDevice::USBDesc_HandleControl(XboxDeviceState* dev, USBPacket *p, int
|
|||
// From the standard: "This request sets the device configuration. The lower byte of the wValue field specifies the desired configuration.
|
||||
// This configuration value must be zero or match a configuration value from a configuration descriptor"
|
||||
ret = USBDesc_SetConfig(dev, value);
|
||||
log_debug("Received standard SetConfiguration() request for device at address 0x%X. Configuration selected is %d and returned %d",
|
||||
log_debug("USB: Received standard SetConfiguration() request for device at address 0x%X. Configuration selected is %d and returned %d",
|
||||
dev->Addr, value, ret);
|
||||
break;
|
||||
}
|
||||
|
@ -908,7 +924,7 @@ int USBPCIDevice::USBDesc_HandleControl(XboxDeviceState* dev, USBPacket *p, int
|
|||
dev->RemoteWakeup = 0;
|
||||
ret = 0;
|
||||
}
|
||||
log_debug("Received standard ClearFeature() request for device at address 0x%X. Feature selected is %d and returned %d",
|
||||
log_debug("USB: Received standard ClearFeature() request for device at address 0x%X. Feature selected is %d and returned %d",
|
||||
dev->Addr, value, ret);
|
||||
break;
|
||||
}
|
||||
|
@ -921,7 +937,7 @@ int USBPCIDevice::USBDesc_HandleControl(XboxDeviceState* dev, USBPacket *p, int
|
|||
dev->RemoteWakeup = 1;
|
||||
ret = 0;
|
||||
}
|
||||
log_debug("Received standard SetFeature() request for device at address 0x%X. Feature selected is %d and returned %d",
|
||||
log_debug("USB: Received standard SetFeature() request for device at address 0x%X. Feature selected is %d and returned %d",
|
||||
dev->Addr, value, ret);
|
||||
break;
|
||||
}
|
||||
|
@ -944,11 +960,12 @@ int USBPCIDevice::USBDesc_HandleControl(XboxDeviceState* dev, USBPacket *p, int
|
|||
// From the standard: "This request allows the host to select an alternate setting for the specified interface"
|
||||
// wValue = Alternative Setting; wIndex = Interface
|
||||
ret = USBDesc_SetInterface(dev, index, value);
|
||||
log_debug("Received standard SetInterface() request for device at address 0x%X. Interface selected is %d, Alternative Setting is %d and returned %d", dev->Addr, index, value, ret);
|
||||
log_debug("USB: Received standard SetInterface() request for device at address 0x%X. Interface selected is %d, Alternative Setting is %d and returned %d", dev->Addr, index, value, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -970,7 +987,7 @@ int USBPCIDevice::USBDesc_HandleStandardGetDescriptor(XboxDeviceState* dev, USBP
|
|||
case USB_DT_DEVICE:
|
||||
{
|
||||
ret = USB_ReadDeviceDesc(&desc->id, dev->Device, buf, sizeof(buf));
|
||||
log_debug("Read operation of device descriptor of device 0x%X returns %d", dev->Addr, ret);
|
||||
log_debug("USB: Read operation of device descriptor of device 0x%X returns %d", dev->Addr, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -979,14 +996,14 @@ int USBPCIDevice::USBDesc_HandleStandardGetDescriptor(XboxDeviceState* dev, USBP
|
|||
if (index < dev->Device->bNumConfigurations) {
|
||||
ret = USB_ReadConfigurationDesc(dev->Device->confs + index, flags, buf, sizeof(buf));
|
||||
}
|
||||
log_debug("Read operation of configuration descriptor %d of device 0x%X returns %d", index, dev->Addr, ret);
|
||||
log_debug("USB: Read operation of configuration descriptor %d of device 0x%X returns %d", index, dev->Addr, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_DT_STRING:
|
||||
{
|
||||
ret = USB_ReadStringDesc(dev, index, buf, sizeof(buf));
|
||||
log_debug("Read operation of string descriptor %d of device 0x%X returns %d", index, dev->Addr, ret);
|
||||
log_debug("USB: Read operation of string descriptor %d of device 0x%X returns %d", index, dev->Addr, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -994,7 +1011,7 @@ int USBPCIDevice::USBDesc_HandleStandardGetDescriptor(XboxDeviceState* dev, USBP
|
|||
// USB_DT_BOS (15) and USB_DT_DEBUG (10) -> usb 3.0 only
|
||||
|
||||
default:
|
||||
log_warning("%s: device address %d unknown type %d (len %zd)", __func__, dev->Addr, type, len);
|
||||
log_warning("USB: %s: device address %d unknown type %d (len %zd)", __func__, dev->Addr, type, len);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1079,7 +1096,7 @@ int USBPCIDevice::USB_ReadConfigurationDesc(const USBDescConfig* conf, int flags
|
|||
}
|
||||
|
||||
int USBPCIDevice::USB_ReadInterfaceDesc(const USBDescIface* iface, int flags, uint8_t* dest, size_t len) {
|
||||
uint8_t bLength = 0x09; // a interface descriptor is 9 bytes large
|
||||
uint8_t bLength = 0x09; // an interface descriptor is 9 bytes large
|
||||
int i, rc, pos = 0;
|
||||
USBDescriptor* d = reinterpret_cast<USBDescriptor*>(dest);
|
||||
|
||||
|
@ -1175,7 +1192,7 @@ int USBPCIDevice::USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* d
|
|||
}
|
||||
|
||||
// From the standard: "String index zero for all languages returns a string descriptor
|
||||
// that contains an array of two-byte LANGID codes supported by the device."
|
||||
// that contains an array of two-byte LANGID codes supported by the device"
|
||||
|
||||
if (index == 0) {
|
||||
/* language ids */
|
||||
|
@ -1205,7 +1222,7 @@ int USBPCIDevice::USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* d
|
|||
return pos;
|
||||
}
|
||||
|
||||
void USBPCIDevice::USBDesc_SetString(XboxDeviceState* dev, int index, const char* str) {
|
||||
void USBPCIDevice::USBDesc_SetString(XboxDeviceState* dev, int index, std::string&& str) {
|
||||
USBDescString* s;
|
||||
|
||||
QLIST_FOREACH(s, &dev->Strings, next) {
|
||||
|
|
|
@ -81,23 +81,25 @@ public:
|
|||
OHCI* m_HostController;
|
||||
// PCI path of this usb device
|
||||
const char* m_PciPath;
|
||||
// free usb ports on this device (hubs included)
|
||||
std::vector<USBPort*> m_FreePorts;
|
||||
|
||||
// register a port with the HC
|
||||
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask, USBPortOps* Ops);
|
||||
// free a port with the HC
|
||||
void USB_UnregisterPort(USBPort* Port);
|
||||
// reset a usb port
|
||||
void USB_PortReset(USBPort* Port);
|
||||
// update device status during an attach
|
||||
void USB_DeviceAttach(XboxDeviceState* dev);
|
||||
// update device status during an detach
|
||||
void USB_DeviceDetach(XboxDeviceState* dev);
|
||||
// update port status when a device is attached
|
||||
void USB_Attach(USBPort* Port);
|
||||
// update port status when a device is detached
|
||||
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);
|
||||
// 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);
|
||||
// find the device connected to the supplied port and address
|
||||
|
@ -156,7 +158,7 @@ public:
|
|||
// 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);
|
||||
void 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)
|
||||
|
@ -166,7 +168,7 @@ public:
|
|||
// reset all endpoints of this peripheral
|
||||
void USB_EpReset(XboxDeviceState* dev);
|
||||
// create a serial number for the device
|
||||
void USB_CreateSerial(XboxDeviceState* dev, const char* str);
|
||||
void USB_CreateSerial(XboxDeviceState* dev, std::string&& str);
|
||||
// start descriptors initialization
|
||||
void USBDesc_Init(XboxDeviceState* dev);
|
||||
// get device descriptor
|
||||
|
@ -198,7 +200,7 @@ public:
|
|||
// return the binary rapresentation of string descriptors
|
||||
int USB_ReadStringDesc(XboxDeviceState* dev, int index, uint8_t* dest, size_t len);
|
||||
// set a string in the string descriptor with the supplied index
|
||||
void USBDesc_SetString(XboxDeviceState* dev, int index, const char* str);
|
||||
void USBDesc_SetString(XboxDeviceState* dev, int index, std::string&& str);
|
||||
// get a string in the string descriptor with the supplied index
|
||||
const char* USBDesc_GetString(XboxDeviceState* dev, int index);
|
||||
private:
|
||||
|
|
445
src/core/openxbox/hw/xid/xid_gamepad.cpp
Normal file
445
src/core/openxbox/hw/xid/xid_gamepad.cpp
Normal file
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->usb->XidGamepad.cpp
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "xid_gamepad.h"
|
||||
#include "../pci/usb_pci.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
XidGamepad* g_XidControllerObjArray[4];
|
||||
|
||||
#define USB_CLASS_XID 0x58
|
||||
#define USB_DT_XID 0x42
|
||||
|
||||
#define HID_GET_REPORT 0x01
|
||||
#define HID_SET_REPORT 0x09
|
||||
#define XID_GET_CAPABILITIES 0x01
|
||||
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
/* Class-specific xid descriptor */
|
||||
struct XIDDesc {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdXid;
|
||||
uint8_t bType;
|
||||
uint8_t bSubType;
|
||||
uint8_t bMaxInputReportSize;
|
||||
uint8_t bMaxOutputReportSize;
|
||||
uint16_t wAlternateProductIds[4];
|
||||
XIDDesc();
|
||||
};
|
||||
|
||||
/* Struct used by the Get_Report request -> state of the buttons */
|
||||
struct XIDGamepadReport {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
uint16_t wButtons; // all non-analog buttons
|
||||
uint8_t bAnalogButtons[8]; // X, Y, A, B, white, black, left/right trigger
|
||||
int16_t sThumbLX; // analog stick, left X
|
||||
int16_t sThumbLY; // analog stick, left Y
|
||||
int16_t sThumbRX; // analog stick, right X
|
||||
int16_t sThumbRY; // analog stick, right Y
|
||||
};
|
||||
|
||||
/* Struct used by the Set_Report request -> vibration strenght */
|
||||
struct XIDGamepadOutputReport {
|
||||
uint8_t report_id; // From XQEMU: FIXME: is this correct?
|
||||
uint8_t length;
|
||||
uint16_t left_actuator_strength; // strenght of left vibration motor
|
||||
uint16_t right_actuator_strength; // strenght of right vibration motor
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
struct USBXIDState {
|
||||
XboxDeviceState dev; // gamepad device status
|
||||
USBEndpoint* intr; // interrupt endpoint of the gamepad
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
USBDescIface::~USBDescIface() {
|
||||
delete[] eps;
|
||||
}
|
||||
|
||||
static const USBDescIface 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;
|
||||
}
|
||||
|
||||
USBDescDevice::~USBDescDevice() {
|
||||
delete confs;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
int XidGamepad::Init(int port) {
|
||||
if (port > 4 || port < 1) { return -1; };
|
||||
|
||||
XboxDeviceState* dev = ClassInitFn();
|
||||
int rc = UsbXidClaimPort(dev, port);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_EpInit(dev);
|
||||
m_UsbDev->USB_DeviceInit(dev);
|
||||
m_UsbDev->USB_DeviceAttach(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XboxDeviceState* XidGamepad::ClassInitFn() {
|
||||
m_pPeripheralFuncStruct = new USBDeviceClass();
|
||||
m_XidState = new USBXIDState();
|
||||
XboxDeviceState* dev = &m_XidState->dev;
|
||||
|
||||
dev->ProductDesc = "Microsoft Xbox Controller";
|
||||
QLIST_INIT(&dev->Strings);
|
||||
dev->klass = m_pPeripheralFuncStruct;
|
||||
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
m_pPeripheralFuncStruct->init = std::bind(&XidGamepad::UsbXid_Initfn, this, _1);
|
||||
m_pPeripheralFuncStruct->handle_reset = std::bind(&XidGamepad::UsbXid_HandleReset, this);
|
||||
m_pPeripheralFuncStruct->handle_control = std::bind(&XidGamepad::UsbXid_HandleControl, this, _1, _2, _3, _4, _5, _6, _7);
|
||||
m_pPeripheralFuncStruct->handle_data = std::bind(&XidGamepad::UsbXid_HandleData, this, _1, _2);
|
||||
m_pPeripheralFuncStruct->handle_destroy = std::bind(&XidGamepad::UsbXid_HandleDestroy, this);
|
||||
m_pPeripheralFuncStruct->handle_attach = std::bind(&XidGamepad::UsbXid_Attach, this, _1);
|
||||
m_pPeripheralFuncStruct->product_desc = dev->ProductDesc.c_str();
|
||||
m_pPeripheralFuncStruct->usb_desc = &desc_xbox_gamepad;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
int XidGamepad::UsbXidClaimPort(XboxDeviceState* dev, int port) {
|
||||
int i;
|
||||
int port_offset;
|
||||
std::vector<USBPort*>::iterator it;
|
||||
|
||||
assert(dev->Port == nullptr);
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (g_HubObjArray[j]) {
|
||||
i = 0;
|
||||
for (auto usb_port : g_HubObjArray[j]->m_UsbDev->m_FreePorts) {
|
||||
if (usb_port->Path == (std::to_string(port) + ".2")) {
|
||||
m_UsbDev = g_HubObjArray[j]->m_UsbDev;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_UsbDev == nullptr) {
|
||||
log_warning("XID: Port requested %d.2 not found (in use?)", port);
|
||||
return -1;
|
||||
}
|
||||
m_Port = port;
|
||||
it = m_UsbDev->m_FreePorts.begin() + i;
|
||||
dev->Port = *it;
|
||||
(*it)->Dev = dev;
|
||||
m_UsbDev->m_FreePorts.erase(it);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXidReleasePort(XboxDeviceState* dev) {
|
||||
USBPort* port = dev->Port;
|
||||
|
||||
assert(port != nullptr);
|
||||
|
||||
port->Dev = nullptr;
|
||||
dev->Port = nullptr;
|
||||
}
|
||||
|
||||
int XidGamepad::UsbXid_Initfn(XboxDeviceState* dev) {
|
||||
m_UsbDev->USB_CreateSerial(dev, std::string("1"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_MANUFACTURER, std::string("Cxbx-Reloaded"));
|
||||
m_UsbDev->USBDesc_SetString(dev, STR_PRODUCT, std::string("Microsoft Gamepad"));
|
||||
m_UsbDev->USBDesc_Init(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->out_state.length = sizeof(m_XidState->out_state);
|
||||
m_XidState->xid_desc = &desc_xid_xbox_gamepad;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleDestroy() {
|
||||
UsbXidReleasePort(&m_XidState->dev);
|
||||
XidCleanUp();
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_Attach(XboxDeviceState* dev) {
|
||||
if ((dev->Port->SpeedMask & USB_SPEED_MASK_FULL)) {
|
||||
dev->Speed = USB_SPEED_FULL;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
m_UsbDev->USBDesc_SetDefaults(dev);
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleReset() {
|
||||
log_debug("XID: Gamepad reset event");
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleControl(XboxDeviceState* dev, USBPacket* p,
|
||||
int request, int value, int index, int length, uint8_t* data) {
|
||||
int ret = m_UsbDev->USBDesc_HandleControl(dev, p, request, value, index, length, data);
|
||||
if (ret >= 0) {
|
||||
log_debug("XID: Gamepad handled by USBDesc_HandleControl, ret is %d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request) {
|
||||
// HID-specific requests
|
||||
case ClassInterfaceRequest | HID_GET_REPORT:
|
||||
{
|
||||
// From the HID standard: "The Get_Report request allows the host to receive a report via the Control pipe.
|
||||
// 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;
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ClassInterfaceOutRequest | HID_SET_REPORT:
|
||||
{
|
||||
// From the HID standard: "The Set_Report request allows the host to send a report to the device, possibly
|
||||
// setting the state of input, output, or feature controls. The meaning of the request fields for the Set_Report
|
||||
// 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;
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// XID-specific requests
|
||||
case VendorInterfaceRequest | USB_REQ_GET_DESCRIPTOR:
|
||||
{
|
||||
log_debug("XID: Gamepad GET_DESCRIPTOR 0x%x", value);
|
||||
if (value == 0x4200) {
|
||||
assert(m_XidState->xid_desc->bLength <= length);
|
||||
std::memcpy(data, m_XidState->xid_desc, m_XidState->xid_desc->bLength);
|
||||
p->ActualLength = m_XidState->xid_desc->bLength;
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VendorInterfaceRequest | XID_GET_CAPABILITIES:
|
||||
{
|
||||
log_debug("XID: Gamepad XID_GET_CAPABILITIES 0x%x", value);
|
||||
/* FIXME: ! */
|
||||
p->Status = USB_RET_STALL;
|
||||
//assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8) | USB_REQ_GET_DESCRIPTOR:
|
||||
{
|
||||
/* FIXME: ! */
|
||||
log_debug("XID: Gamepad unknown xpad request 0x%X: value = 0x%X", request, value);
|
||||
std::memset(data, 0x00, length);
|
||||
//FIXME: Intended for the hub: usbd_get_hub_descriptor, UT_READ_CLASS?!
|
||||
p->Status = USB_RET_STALL;
|
||||
//assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) << 8) | USB_REQ_CLEAR_FEATURE:
|
||||
{
|
||||
/* FIXME: ! */
|
||||
log_debug("XID: Gamepad unknown xpad request 0x%X: value = 0x%X", request, value);
|
||||
std::memset(data, 0x00, length);
|
||||
p->Status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
log_debug("XID: Gamepad USB stalled on request 0x%X value 0x%X", request, value);
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XidGamepad::UsbXid_HandleData(XboxDeviceState* dev, USBPacket* p) {
|
||||
switch (p->Pid) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case USB_TOKEN_OUT:
|
||||
{
|
||||
p->Status = USB_RET_STALL;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
p->Status = USB_RET_STALL;
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void XidGamepad::XidCleanUp() {
|
||||
delete m_pPeripheralFuncStruct;
|
||||
delete m_XidState;
|
||||
m_pPeripheralFuncStruct = nullptr;
|
||||
m_XidState = nullptr;
|
||||
}
|
||||
|
||||
}
|
86
src/core/openxbox/hw/xid/xid_gamepad.h
Normal file
86
src/core/openxbox/hw/xid/xid_gamepad.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Portions of the code are based on Cxbx-Reloaded's OHCI LLE implementation.
|
||||
* The original copyright header is included below.
|
||||
*/
|
||||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * .,-::::: .,:: .::::::::. .,:: .:
|
||||
// * ,;;;'````' `;;;, .,;; ;;;'';;' `;;;, .,;;
|
||||
// * [[[ '[[,,[[' [[[__[[\. '[[,,[['
|
||||
// * $$$ Y$$$P $$""""Y$$ Y$$$P
|
||||
// * `88bo,__,o, oP"``"Yo, _88o,,od8P oP"``"Yo,
|
||||
// * "YUMMMMMP",m" "Mm,""YUMMMP" ,m" "Mm,
|
||||
// *
|
||||
// * Cxbx->devices->usb->XidGamepad.h
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "../ohci/ohci_hub.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
struct USBXIDState; // forward declare
|
||||
|
||||
/* Class which implements an xbox gamepad */
|
||||
class XidGamepad {
|
||||
public:
|
||||
// initialize this peripheral
|
||||
int Init(int port);
|
||||
// destroy gamepad resources
|
||||
void XidCleanUp();
|
||||
|
||||
|
||||
private:
|
||||
// usb device this gamepad is attached to through the hub
|
||||
USBPCIDevice* m_UsbDev = nullptr;
|
||||
// gamepad state
|
||||
USBXIDState* m_XidState = nullptr;
|
||||
// gamepad class functions
|
||||
USBDeviceClass* m_pPeripheralFuncStruct = nullptr;
|
||||
// xbox port this gamepad is attached to
|
||||
int m_Port = 0;
|
||||
|
||||
// initialize various member variables/functions
|
||||
XboxDeviceState* ClassInitFn();
|
||||
// reserve a usb port for this gamepad
|
||||
int UsbXidClaimPort(XboxDeviceState* dev, int port);
|
||||
// free the usb port used by this gamepad
|
||||
void UsbXidReleasePort(XboxDeviceState* dev);
|
||||
// see USBDeviceClass for comments about these functions
|
||||
int UsbXid_Initfn(XboxDeviceState* dev);
|
||||
void UsbXid_HandleDestroy();
|
||||
void UsbXid_Attach(XboxDeviceState* dev);
|
||||
void UsbXid_HandleReset();
|
||||
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);
|
||||
};
|
||||
|
||||
extern XidGamepad* g_XidControllerObjArray[4];
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#include "openxbox/platform.h"
|
||||
#include "openxbox/settings.h"
|
||||
#include "openxbox/pte.h"
|
||||
#include "openxbox/log.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
@ -10,3 +11,4 @@
|
|||
#include <stack>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <cassert>
|
||||
|
|
Loading…
Reference in a new issue