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:
StrikerX3 2018-07-18 22:57:06 -03:00
parent e233726f9e
commit c3dd820d31
12 changed files with 1084 additions and 261 deletions

View file

@ -89,6 +89,10 @@ void ClockThread(TimerObject* Timer) {
return;
}
Timer->Callback(Timer->Opaque);
if (Timer->Exit.load()) {
Timer_Destroy(Timer);
return;
}
NewExpireTime = GetNextExpireTime(Timer);
}
}

View file

@ -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)

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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];

View file

@ -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) {

View file

@ -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:

View 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;
}
}

View 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];
}

View file

@ -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>