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 bc5283b
This commit is contained in:
parent
7c9eee188c
commit
8f2747a530
|
@ -42,19 +42,17 @@
|
|||
namespace openxbox {
|
||||
|
||||
/* This is a linux struct for vectored I/O. See readv() and writev() */
|
||||
typedef struct _IoVec {
|
||||
struct IoVec {
|
||||
void* Iov_Base; // Starting address
|
||||
size_t Iov_Len; // Number of bytes to transfer
|
||||
}
|
||||
IoVec;
|
||||
};
|
||||
|
||||
typedef struct _IOVector {
|
||||
struct IOVector {
|
||||
IoVec* IoVecStruct;
|
||||
int IoVecNumber; // number of I/O buffers supplied
|
||||
int AllocNumber; // number of IoVec structs currently allocated
|
||||
size_t Size; // total size of all I/O buffers supplied
|
||||
}
|
||||
IOVector;
|
||||
};
|
||||
|
||||
inline uint64_t Muldiv64(uint64_t a, uint32_t b, uint32_t c);
|
||||
|
||||
|
@ -63,4 +61,11 @@ void IoVecAdd(IOVector* qiov, void* base, size_t len);
|
|||
size_t IoVecTobuffer(const IoVec* iov, const unsigned int iov_cnt, size_t offset, void *buf, size_t bytes);
|
||||
size_t IoVecFromBuffer(const IoVec* iov, unsigned int iov_cnt, size_t offset, void* buf, size_t bytes);
|
||||
|
||||
// Calculate a struct base address from a pointer to a member of it
|
||||
#ifndef container_of
|
||||
#define container_of(address, type, field) ((type *)(\
|
||||
(int8_t*)(address) - \
|
||||
(uint32_t)(&((type *)0)->field)))
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -39,37 +39,6 @@
|
|||
|
||||
namespace openxbox {
|
||||
|
||||
// ergo720: note that GetDwords and WriteDwords will reliably work only if the allocation was served by MapViewOfFileEx and not
|
||||
// by VirtualAlloc (see comment on OHCI_ReadHCCA for more details). Once LLE CPU and MMU are implemented, this will no
|
||||
// longer be the case. Also note that the physical pages can be modified while being read/written
|
||||
|
||||
// read an array of DWORDs in memory
|
||||
void GetDwords(uint32_t Paddr, uint32_t* Buffer, int Number) {
|
||||
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
|
||||
std::memcpy(Buffer, reinterpret_cast<void*>(Paddr + CONTIGUOUS_MEMORY_BASE), 4); // dropped little -> big endian conversion from XQEMU
|
||||
}
|
||||
}
|
||||
|
||||
// write an array of DWORDs in memory
|
||||
void WriteDwords(uint32_t Paddr, uint32_t* Buffer, int Number) {
|
||||
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
|
||||
std::memcpy(reinterpret_cast<void*>(Paddr + CONTIGUOUS_MEMORY_BASE), Buffer, 4); // dropped big -> little endian conversion from XQEMU
|
||||
}
|
||||
}
|
||||
|
||||
// read an array of WORDs in memory
|
||||
void GetWords(uint32_t Paddr, uint16_t* Buffer, int Number) {
|
||||
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
|
||||
std::memcpy(Buffer, reinterpret_cast<void*>(Paddr + CONTIGUOUS_MEMORY_BASE), 2); // dropped little -> big endian conversion from XQEMU
|
||||
}
|
||||
}
|
||||
|
||||
// write an array of WORDs in memory
|
||||
void WriteWords(uint32_t Paddr, uint16_t* Buffer, int Number) {
|
||||
for (int i = 0; i < Number; i++, Buffer++, Paddr += sizeof(*Buffer)) {
|
||||
std::memcpy(reinterpret_cast<void*>(Paddr + CONTIGUOUS_MEMORY_BASE), Buffer, 2); // dropped big -> little endian conversion from XQEMU
|
||||
}
|
||||
}
|
||||
|
||||
/* These macros are used to access the bits of the various registers */
|
||||
// HcControl
|
||||
|
@ -211,29 +180,36 @@ void WriteWords(uint32_t Paddr, uint16_t* Buffer, int Number) {
|
|||
|
||||
#define USB_HZ 12000000
|
||||
|
||||
#define USB_SPEED_LOW 0
|
||||
#define USB_SPEED_FULL 1
|
||||
|
||||
#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
|
||||
|
||||
#define OHCI_PAGE_MASK 0xFFFFF000
|
||||
#define OHCI_OFFSET_MASK 0xFFF
|
||||
|
||||
typedef enum _USB_SPEED
|
||||
OHCI::OHCI(Cpu* cpu, int Irq, USBPCIDevice* UsbObj)
|
||||
: m_cpu(cpu)
|
||||
{
|
||||
USB_SPEED_MASK_LOW = 1 << 0,
|
||||
USB_SPEED_MASK_FULL = 1 << 1,
|
||||
}
|
||||
USB_SPEED;
|
||||
int offset = 0;
|
||||
USBPortOps* ops;
|
||||
|
||||
|
||||
OHCI::OHCI(int Irq, USBPCIDevice* UsbObj)
|
||||
{
|
||||
m_IrqNum = Irq;
|
||||
m_UsbDevice = UsbObj;
|
||||
ops = new USBPortOps();
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
ops->attach = std::bind(&OHCI::OHCI_Attach, this, _1);
|
||||
ops->detach = std::bind(&OHCI::OHCI_Detach, this, _1);
|
||||
ops->child_detach = std::bind(&OHCI::OHCI_ChildDetach, this, nullptr, _2);
|
||||
ops->wakeup = std::bind(&OHCI::OHCI_Wakeup, this, _1);
|
||||
ops->complete = std::bind(&OHCI::OHCI_AsyncCompletePacket, this, _1, _2);
|
||||
}
|
||||
|
||||
if (m_IrqNum == 9) {
|
||||
offset = 2;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
m_UsbDevice->USB_RegisterPort(&m_Registers.RhPort[i].UsbPort, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
m_UsbDevice->USB_RegisterPort(&m_Registers.RhPort[i].UsbPort, i + offset, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, ops);
|
||||
}
|
||||
OHCI_PacketInit(&m_UsbPacket);
|
||||
|
||||
|
@ -313,7 +289,7 @@ void OHCI::OHCI_FrameBoundaryWorker()
|
|||
}
|
||||
|
||||
if (m_DoneCount != 7 && m_DoneCount != 0) {
|
||||
// decrease DelayInterrupt counter
|
||||
// decrease Done Queue counter
|
||||
m_DoneCount--;
|
||||
}
|
||||
|
||||
|
@ -374,7 +350,7 @@ bool OHCI::OHCI_WriteHCCA(uint32_t Paddr, OHCI_HCCA* Hcca)
|
|||
bool OHCI::OHCI_ReadED(uint32_t Paddr, OHCI_ED* Ed)
|
||||
{
|
||||
if (Paddr != NULL) {
|
||||
GetDwords(Paddr, reinterpret_cast<uint32_t*>(Ed), sizeof(*Ed) >> 2); // ED is 16 bytes large
|
||||
m_cpu->VMemRead(Paddr, sizeof(*Ed), Ed);
|
||||
return false;
|
||||
}
|
||||
return true; // error
|
||||
|
@ -385,7 +361,7 @@ bool OHCI::OHCI_WriteED(uint32_t Paddr, OHCI_ED* Ed)
|
|||
if (Paddr != NULL) {
|
||||
// According to the standard, only the HeadP field is writable by the HC, so we'll write just that
|
||||
size_t OffsetOfHeadP = offsetof(OHCI_ED, HeadP);
|
||||
WriteDwords(Paddr + OffsetOfHeadP, reinterpret_cast<uint32_t*>(reinterpret_cast<uint8_t*>(Ed) + OffsetOfHeadP), 1);
|
||||
m_cpu->VMemWrite(Paddr, 4, Ed + OffsetOfHeadP);
|
||||
return false;
|
||||
}
|
||||
return true; // error
|
||||
|
@ -394,7 +370,7 @@ bool OHCI::OHCI_WriteED(uint32_t Paddr, OHCI_ED* Ed)
|
|||
bool OHCI::OHCI_ReadTD(uint32_t Paddr, OHCI_TD* Td)
|
||||
{
|
||||
if (Paddr != NULL) {
|
||||
GetDwords(Paddr, reinterpret_cast<uint32_t*>(Td), sizeof(*Td) >> 2); // TD is 16 bytes large
|
||||
m_cpu->VMemRead(Paddr, sizeof(*Td), Td);
|
||||
return false;
|
||||
}
|
||||
return true; // error
|
||||
|
@ -403,7 +379,7 @@ bool OHCI::OHCI_ReadTD(uint32_t Paddr, OHCI_TD* Td)
|
|||
bool OHCI::OHCI_WriteTD(uint32_t Paddr, OHCI_TD* Td)
|
||||
{
|
||||
if (Paddr != NULL) {
|
||||
WriteDwords(Paddr, reinterpret_cast<uint32_t*>(Td), sizeof(*Td) >> 2);
|
||||
m_cpu->VMemWrite(Paddr, sizeof(*Td), Td);
|
||||
return false;
|
||||
}
|
||||
return true; // error
|
||||
|
@ -411,8 +387,7 @@ bool OHCI::OHCI_WriteTD(uint32_t Paddr, OHCI_TD* Td)
|
|||
|
||||
bool OHCI::OHCI_ReadIsoTD(uint32_t Paddr, OHCI_ISO_TD* td) {
|
||||
if (Paddr != NULL) {
|
||||
GetDwords(Paddr, reinterpret_cast<uint32_t*>(td), 4);
|
||||
GetWords(Paddr + 16, td->Offset, 8);
|
||||
m_cpu->VMemRead(Paddr, sizeof(*td), td);
|
||||
return false;
|
||||
}
|
||||
return true; // error
|
||||
|
@ -420,8 +395,7 @@ bool OHCI::OHCI_ReadIsoTD(uint32_t Paddr, OHCI_ISO_TD* td) {
|
|||
|
||||
bool OHCI::OHCI_WriteIsoTD(uint32_t Paddr, OHCI_ISO_TD* td) {
|
||||
if (Paddr != NULL) {
|
||||
WriteDwords(Paddr, reinterpret_cast<uint32_t*>(td), 4);
|
||||
WriteWords(Paddr + 16, td->Offset, 8);
|
||||
m_cpu->VMemWrite(Paddr, sizeof(*td), td);
|
||||
return false;
|
||||
}
|
||||
return true; // error
|
||||
|
@ -599,7 +573,7 @@ int OHCI::OHCI_ServiceTD(OHCI_ED* Ed)
|
|||
int pid;
|
||||
int ret;
|
||||
int i;
|
||||
XboxDevice* dev;
|
||||
XboxDeviceState* dev;
|
||||
USBEndpoint* ep;
|
||||
OHCI_TD td;
|
||||
uint32_t addr;
|
||||
|
@ -845,9 +819,9 @@ exit_no_retire:
|
|||
return OHCI_BM(td.Flags, TD_CC) != OHCI_CC_NOERROR;
|
||||
}
|
||||
|
||||
XboxDevice* OHCI::OHCI_FindDevice(uint8_t Addr)
|
||||
XboxDeviceState* OHCI::OHCI_FindDevice(uint8_t Addr)
|
||||
{
|
||||
XboxDevice* dev;
|
||||
XboxDeviceState* dev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
@ -1277,7 +1251,7 @@ uint32_t OHCI::OHCI_GetFrameRemaining()
|
|||
|
||||
void OHCI::OHCI_StopEndpoints()
|
||||
{
|
||||
XboxDevice* dev;
|
||||
XboxDeviceState* dev;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
@ -1455,7 +1429,7 @@ void OHCI::OHCI_Attach(USBPort* Port)
|
|||
port->HcRhPortStatus |= OHCI_PORT_CCS | OHCI_PORT_CSC;
|
||||
|
||||
// update speed
|
||||
if (port->UsbPort.Dev->speed == USB_SPEED_LOW) {
|
||||
if (port->UsbPort.Dev->Speed == USB_SPEED_LOW) {
|
||||
port->HcRhPortStatus |= OHCI_PORT_LSDA;
|
||||
}
|
||||
else {
|
||||
|
@ -1467,14 +1441,48 @@ void OHCI::OHCI_Attach(USBPort* Port)
|
|||
OHCI_SetInterrupt(OHCI_INTR_RD);
|
||||
}
|
||||
|
||||
log_debug("OHCI: Attached port %d\n", Port->PortIndex);
|
||||
log_debug("OHCI: Attached port %d", Port->PortIndex);
|
||||
|
||||
if (old_state != port->HcRhPortStatus) {
|
||||
OHCI_SetInterrupt(OHCI_INTR_RHSC);
|
||||
}
|
||||
}
|
||||
|
||||
void OHCI::OHCI_AsyncCancelDevice(XboxDevice* dev)
|
||||
void OHCI::OHCI_ChildDetach(USBPort* port, XboxDeviceState* child) {
|
||||
OHCI_AsyncCancelDevice(child);
|
||||
}
|
||||
|
||||
void OHCI::OHCI_Wakeup(USBPort* port1) {
|
||||
OHCIPort* port = &m_Registers.RhPort[port1->PortIndex];
|
||||
uint32_t intr = 0;
|
||||
if (port->HcRhPortStatus & OHCI_PORT_PSS) {
|
||||
log_debug("OHCI: port %d: wakeup", port1->PortIndex);
|
||||
port->HcRhPortStatus |= OHCI_PORT_PSSC;
|
||||
port->HcRhPortStatus &= ~OHCI_PORT_PSS;
|
||||
intr = OHCI_INTR_RHSC;
|
||||
}
|
||||
// Note that the controller can be suspended even if this port is not
|
||||
if ((m_Registers.HcControl & OHCI_CTL_HCFS) == Suspend) {
|
||||
log_debug("OHCI: remote-wakeup: SUSPEND->RESUME");
|
||||
// From the standard: "The only interrupts possible in the USBSUSPEND state are ResumeDetected (the
|
||||
// Host Controller will have changed the HostControllerFunctionalState to the USBRESUME state)
|
||||
// and OwnershipChange."
|
||||
m_Registers.HcControl &= ~OHCI_CTL_HCFS;
|
||||
m_Registers.HcControl |= Resume;
|
||||
intr = OHCI_INTR_RD;
|
||||
}
|
||||
OHCI_SetInterrupt(intr);
|
||||
}
|
||||
|
||||
void OHCI::OHCI_AsyncCompletePacket(USBPort* port, USBPacket* packet) {
|
||||
#ifdef DEBUG_PACKET
|
||||
log_debug("Async packet complete");
|
||||
#endif
|
||||
m_AsyncComplete = 1;
|
||||
OHCI_ProcessLists(1);
|
||||
}
|
||||
|
||||
void OHCI::OHCI_AsyncCancelDevice(XboxDeviceState* dev)
|
||||
{
|
||||
if (m_AsyncTD &&
|
||||
m_UsbDevice->USB_IsPacketInflight(&m_UsbPacket) &&
|
||||
|
@ -1518,7 +1526,7 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
|
|||
int pid;
|
||||
int ret;
|
||||
int i;
|
||||
XboxDevice* dev;
|
||||
XboxDeviceState* dev;
|
||||
USBEndpoint* ep;
|
||||
OHCI_ISO_TD iso_td;
|
||||
uint32_t addr;
|
||||
|
@ -1670,7 +1678,7 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
|
|||
}
|
||||
else {
|
||||
// From the standard: "If, however, the data packet is the last in an Isochronous TD(R = FrameCount),
|
||||
// then the value of BufferEnd is the address of the last byte in the buffer."
|
||||
// then the value of BufferEnd is the address of the last byte in the buffer."
|
||||
end_addr = iso_td.BufferEnd;
|
||||
}
|
||||
|
||||
|
@ -1716,7 +1724,8 @@ int OHCI::OHCI_ServiceIsoTD(OHCI_ED* ed, int completion)
|
|||
// From the standard: "After each data packet transfer, the Rth Offset is replaced with a value that indicates the status of
|
||||
// the data packet transfer.The upper 4 bits of the value are the ConditionCode for the transfer and the lower 12 bits
|
||||
// represent the size of the transfer.Together, these two fields constitute the Packet Status Word(PacketStatusWord)."
|
||||
// Writeback
|
||||
|
||||
// Writeback
|
||||
if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
|
||||
// IN transfer succeeded
|
||||
if (OHCI_CopyIsoTD(start_addr, end_addr, m_UsbBuffer, ret, true)) {
|
||||
|
@ -1781,4 +1790,9 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,13 +42,10 @@
|
|||
|
||||
#include "usb_pci.h"
|
||||
#include "openxbox/cxbxtimer.h"
|
||||
#include "openxbox/cpu.h"
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
#define USB_TOKEN_SETUP 0x2D
|
||||
#define USB_TOKEN_IN 0x69 // device -> host
|
||||
#define USB_TOKEN_OUT 0xE1 // host -> device
|
||||
|
||||
#define USB_RET_SUCCESS (0)
|
||||
#define USB_RET_NODEV (-1)
|
||||
#define USB_RET_NAK (-2)
|
||||
|
@ -71,32 +68,29 @@ namespace openxbox {
|
|||
|
||||
|
||||
/* endpoint descriptor */
|
||||
typedef struct _OHCI_ED {
|
||||
struct OHCI_ED {
|
||||
uint32_t Flags;
|
||||
uint32_t TailP;
|
||||
uint32_t HeadP;
|
||||
uint32_t NextED;
|
||||
}
|
||||
OHCI_ED;
|
||||
};
|
||||
|
||||
/* general transfer descriptor */
|
||||
typedef struct _OHCI_TD {
|
||||
struct OHCI_TD {
|
||||
uint32_t Flags;
|
||||
uint32_t CurrentBufferPointer;
|
||||
uint32_t NextTD;
|
||||
uint32_t BufferEnd;
|
||||
}
|
||||
OHCI_TD;
|
||||
};
|
||||
|
||||
/* Isochronous transfer descriptor */
|
||||
typedef struct _OHCI_ISO_TD {
|
||||
struct OHCI_ISO_TD {
|
||||
uint32_t Flags;
|
||||
uint32_t BufferPage0;
|
||||
uint32_t NextTD;
|
||||
uint32_t BufferEnd;
|
||||
uint16_t Offset[8];
|
||||
}
|
||||
OHCI_ISO_TD;
|
||||
};
|
||||
|
||||
/* enum indicating the current HC state */
|
||||
typedef enum _OHCI_State {
|
||||
|
@ -108,22 +102,20 @@ typedef enum _OHCI_State {
|
|||
OHCI_State;
|
||||
|
||||
/* Host Controller Communications Area */
|
||||
typedef struct _OHCI_HCCA {
|
||||
struct OHCI_HCCA {
|
||||
uint32_t HccaInterrruptTable[32];
|
||||
uint16_t HccaFrameNumber, HccaPad1;
|
||||
uint32_t HccaDoneHead;
|
||||
}
|
||||
OHCI_HCCA;
|
||||
};
|
||||
|
||||
/* Small struct used to hold the HcRhPortStatus register and the usb port status */
|
||||
typedef struct _OHCIPort {
|
||||
struct OHCIPort {
|
||||
USBPort UsbPort;
|
||||
uint32_t HcRhPortStatus;
|
||||
}
|
||||
OHCIPort;
|
||||
};
|
||||
|
||||
/* All these registers are well documented in the OHCI standard */
|
||||
typedef struct _OHCI_Registers {
|
||||
struct OHCI_Registers {
|
||||
// Control and Status partition
|
||||
uint32_t HcRevision;
|
||||
uint32_t HcControl;
|
||||
|
@ -152,32 +144,28 @@ typedef struct _OHCI_Registers {
|
|||
uint32_t HcRhDescriptorA;
|
||||
uint32_t HcRhDescriptorB;
|
||||
uint32_t HcRhStatus;
|
||||
// ergo720: I have some doubts here. Both XQEMU and OpenXbox set 4 ports per HC, for a total of 8 usb ports.
|
||||
// Could it be becasue each gamepad can host 2 memory units?
|
||||
OHCIPort RhPort[2]; // 2 ports per HC, for a total of 4 USB ports
|
||||
}
|
||||
OHCI_Registers;
|
||||
};
|
||||
|
||||
|
||||
/* OHCI class representing the state of the HC */
|
||||
class OHCI {
|
||||
public:
|
||||
// constructor
|
||||
OHCI(int Irqn, USBPCIDevice* UsbObj);
|
||||
OHCI(Cpu* cpu, int Irqn, USBPCIDevice* UsbObj);
|
||||
// destructor
|
||||
~OHCI() {}
|
||||
// read a register
|
||||
uint32_t OHCI_ReadRegister(uint32_t Addr);
|
||||
// write a register
|
||||
void OHCI_WriteRegister(uint32_t Addr, uint32_t Value);
|
||||
// update ohci registers during a device attach
|
||||
void OHCI_Attach(USBPort* Port);
|
||||
// update ohci registers during a device detach
|
||||
void OHCI_Detach(USBPort* Port);
|
||||
// update the USBPort struct with the device attached
|
||||
void OHCI_AssignUsbPortStruct(int port, XboxDeviceState* dev);
|
||||
|
||||
private:
|
||||
Cpu* m_cpu;
|
||||
// pointer to g_USB0 or g_USB1
|
||||
USBPCIDevice * m_UsbDevice = nullptr;
|
||||
USBPCIDevice* m_UsbDevice = nullptr;
|
||||
// all the registers available on the OHCI standard
|
||||
OHCI_Registers m_Registers;
|
||||
// end-of-frame timer
|
||||
|
@ -267,11 +255,17 @@ private:
|
|||
// process an isochronous TD
|
||||
int OHCI_ServiceIsoTD(OHCI_ED* ed, int completion);
|
||||
// find the usb device with the supplied address
|
||||
XboxDevice* OHCI::OHCI_FindDevice(uint8_t Addr);
|
||||
XboxDeviceState* OHCI::OHCI_FindDevice(uint8_t Addr);
|
||||
// cancel a packet when a device is removed
|
||||
void OHCI_AsyncCancelDevice(XboxDevice* dev);
|
||||
void OHCI_AsyncCancelDevice(XboxDeviceState* dev);
|
||||
// Process Control and Bulk lists
|
||||
void OHCI_ProcessLists(int completion);
|
||||
// see USBPortOps struct for info
|
||||
void OHCI_Attach(USBPort* Port);
|
||||
void OHCI_Detach(USBPort* Port);
|
||||
void OHCI_ChildDetach(USBPort* port, XboxDeviceState* child);
|
||||
void OHCI_Wakeup(USBPort* port1);
|
||||
void OHCI_AsyncCompletePacket(USBPort* port, USBPacket* packet);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
349
src/core/openxbox/hw/pci/ohci_common.h
Normal file
349
src/core/openxbox/hw/pci/ohci_common.h
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* 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->UsbCommon.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
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openxbox/queue.h"
|
||||
#include "openxbox/iovec.h"
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
#define USB_MAX_ENDPOINTS 15
|
||||
#define USB_MAX_INTERFACES 16
|
||||
|
||||
#define USB_STATE_NOTATTACHED 0
|
||||
#define USB_STATE_ATTACHED 1
|
||||
#define USB_STATE_DEFAULT 2
|
||||
|
||||
#define USB_CLASS_HUB 9
|
||||
|
||||
#define USB_ENDPOINT_XFER_CONTROL 0
|
||||
#define USB_ENDPOINT_XFER_ISOC 1
|
||||
#define USB_ENDPOINT_XFER_BULK 2
|
||||
#define USB_ENDPOINT_XFER_INT 3
|
||||
#define USB_ENDPOINT_XFER_INVALID 255
|
||||
|
||||
#define USB_INTERFACE_INVALID 255
|
||||
|
||||
#define USB_DIR_OUT 0
|
||||
#define USB_DIR_IN 0x80
|
||||
|
||||
#define USB_TOKEN_SETUP 0x2D
|
||||
#define USB_TOKEN_IN 0x69 // device -> host
|
||||
#define USB_TOKEN_OUT 0xE1 // host -> device
|
||||
|
||||
#define USB_SPEED_LOW 0
|
||||
#define USB_SPEED_FULL 1
|
||||
|
||||
typedef enum _USB_SPEED {
|
||||
USB_SPEED_MASK_LOW = 1 << 0,
|
||||
USB_SPEED_MASK_FULL = 1 << 1,
|
||||
}
|
||||
USB_SPEED;
|
||||
|
||||
typedef enum USBPacketState {
|
||||
USB_PACKET_UNDEFINED = 0,
|
||||
USB_PACKET_SETUP,
|
||||
USB_PACKET_QUEUED,
|
||||
USB_PACKET_ASYNC,
|
||||
USB_PACKET_COMPLETE,
|
||||
USB_PACKET_CANCELED,
|
||||
}
|
||||
USBPacketState;
|
||||
|
||||
struct USBPacket;
|
||||
struct USBPort;
|
||||
struct USBDeviceClass;
|
||||
struct XboxDeviceState;
|
||||
|
||||
typedef const char* USBDescStrings[256];
|
||||
|
||||
/* String descriptor */
|
||||
struct USBDescString {
|
||||
uint8_t index; // index of this string descriptor
|
||||
std::string str; // the string of this string descriptor
|
||||
QLIST_ENTRY(USBDescString) next;
|
||||
};
|
||||
|
||||
struct USBDescOther {
|
||||
uint8_t length;
|
||||
const uint8_t *data;
|
||||
};
|
||||
|
||||
/* Endpoint descriptor */
|
||||
struct USBDescEndpoint {
|
||||
uint8_t bEndpointAddress; // the address of the endpoint on the USB device described by this descriptor
|
||||
uint8_t bmAttributes; // this field describes the endpoint's attributes when it is configured using the bConfigurationValue
|
||||
uint16_t wMaxPacketSize; // maximum packet size this endpoint is capable of sending or receiving when this configuration is selected
|
||||
uint8_t bInterval; // interval for polling endpoint for data transfers, expressed in milliseconds.
|
||||
uint8_t bRefresh; // for audio devices only: the rate at which synchronization feedback is provided
|
||||
uint8_t bSynchAddress; // for audio devices only: the address of the synchronization endpoint
|
||||
|
||||
uint8_t is_audio; /* has bRefresh + bSynchAddress */
|
||||
uint8_t* extra;
|
||||
};
|
||||
|
||||
/* Interface descriptor */
|
||||
struct USBDescIface {
|
||||
uint8_t bInterfaceNumber; // number of interface
|
||||
uint8_t bAlternateSetting; // value used to select the alternate setting for the interface identified by bInterfaceNumber
|
||||
uint8_t bNumEndpoints; // number of endpoints used by this interface (excluding endpoint zero)
|
||||
uint8_t bInterfaceClass; // class code (assigned by the USB)
|
||||
uint8_t bInterfaceSubClass; // subclass code (assigned by the USB)
|
||||
uint8_t bInterfaceProtocol; // protocol code (assigned by the USB)
|
||||
uint8_t iInterface; // index of string descriptor describing this interface
|
||||
|
||||
uint8_t ndesc;
|
||||
USBDescOther* descs;
|
||||
USBDescEndpoint* eps; // endpoints supported by this interface
|
||||
USBDescIface(bool bDefault);
|
||||
~USBDescIface();
|
||||
};
|
||||
|
||||
/*
|
||||
* ergo720: I removed the Interface Association Descriptor (IAD) since, at the time of this writing (2018), the xboxdevwiki documents that all
|
||||
* known xid devices don't use them and also, according to the corresponding standard, IAD applies to usb revision 2.0 while the xbox uses
|
||||
* usb revision 1.1 so it shouldn't support them either. If this turns out to be incorrect, then IAD support will have to be added
|
||||
*/
|
||||
|
||||
/* Configuration descriptor */
|
||||
struct USBDescConfig {
|
||||
uint8_t bNumInterfaces; // number of interfaces supported by this configuration
|
||||
uint8_t bConfigurationValue; // value to use as an argument to the SetConfiguration() request to select this configuration
|
||||
uint8_t iConfiguration; // index of string descriptor describing this configuration
|
||||
uint8_t bmAttributes; // configuration characteristics
|
||||
uint8_t bMaxPower; // maximum power consumption of the USB device in this configuration expressed in 2mA units
|
||||
|
||||
/* "normal" interfaces */
|
||||
uint8_t nif; // number of interfaces (again)
|
||||
const USBDescIface* ifs; // interfaces supported by this configuration
|
||||
};
|
||||
|
||||
/* Device descriptor part 1 */
|
||||
struct USBDescDevice {
|
||||
uint16_t bcdUSB; // USB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H)
|
||||
uint8_t bDeviceClass; // class code (assigned by the USB)
|
||||
uint8_t bDeviceSubClass; // subclass code (assigned by the USB)
|
||||
uint8_t bDeviceProtocol; // protocol code (assigned by the USB)
|
||||
uint8_t bMaxPacketSize0; // maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid)
|
||||
uint8_t bNumConfigurations; // number of possible configurations
|
||||
const USBDescConfig* confs; // configurations supported by this device
|
||||
USBDescDevice(bool bDefault);
|
||||
~USBDescDevice();
|
||||
};
|
||||
|
||||
/* Device descriptor part 2 */
|
||||
struct USBDescID {
|
||||
uint16_t idVendor; // vendor ID (assigned by the USB)
|
||||
uint16_t idProduct; // product ID (assigned by the manufacturer)
|
||||
uint16_t bcdDevice; // device release number in binary-coded decimal
|
||||
uint8_t iManufacturer; // index of string descriptor describing manufacturer
|
||||
uint8_t iProduct; // index of string descriptor describing product
|
||||
uint8_t iSerialNumber; // index of string descriptor describing the device’s serial number
|
||||
};
|
||||
|
||||
/* Global USB Descriptor struct */
|
||||
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);
|
||||
};
|
||||
|
||||
/* USB endpoint */
|
||||
struct USBEndpoint {
|
||||
uint8_t Num; // endpoint number
|
||||
uint8_t pid;
|
||||
uint8_t Type; // the type of this endpoint
|
||||
uint8_t IfNum; // interface number this endpoint belongs to
|
||||
int MaxPacketSize; // maximum packet size supported by this endpoint
|
||||
bool Pipeline;
|
||||
bool Halted; // indicates that the endpoint is halted
|
||||
XboxDeviceState* Dev; // device this endpoint belongs to
|
||||
QTAILQ_HEAD(, USBPacket) Queue; // queue of packets to this endpoint
|
||||
};
|
||||
|
||||
/* definition of an Xbox usb device */
|
||||
struct XboxDeviceState {
|
||||
USBPort* Port; // usb port struct of this device
|
||||
int PortPath; // port index to which this device is attached to
|
||||
char* Serial;
|
||||
uint32_t flags;
|
||||
USBDeviceClass* klass; // usb class struct of this device
|
||||
|
||||
int Speed; // actual connected speed
|
||||
int SpeedMask; // supported speeds, not in info because it may be variable (hostdevs)
|
||||
uint8_t Addr; // device function address
|
||||
std::string ProductDesc; // the friendly name of this device
|
||||
int Attached; // device is attached
|
||||
|
||||
int32_t State; // current state of device
|
||||
uint8_t SetupBuffer[8]; // holds the IoVec structs copied (control transfers only?)
|
||||
uint8_t data_buf[4096];
|
||||
int32_t RemoteWakeup; // wakeup flag
|
||||
int32_t SetupState; // result of a setup tken processing operation
|
||||
int32_t SetupLength; // number of bytes to transfer as specified by a setup token
|
||||
int32_t SetupIndex; // index of the parameter in a setup token?
|
||||
|
||||
USBEndpoint EP_ctl; // endpoints for SETUP tokens
|
||||
USBEndpoint EP_in[USB_MAX_ENDPOINTS]; // endpoints for OUT tokens
|
||||
USBEndpoint EP_out[USB_MAX_ENDPOINTS]; // endpoints for IN tokens
|
||||
|
||||
QLIST_HEAD(, USBDescString) Strings; // strings of the string descriptor
|
||||
const USBDesc* UsbDesc; // Overrides class usb_desc if not nullptr
|
||||
const USBDescDevice* Device; // device descriptor part 1
|
||||
|
||||
int Configuration; // number of the selected configuration descriptor
|
||||
int NumInterfaces; // number of available interface descriptors
|
||||
int AltSetting[USB_MAX_INTERFACES]; // alternate setting numbers for the current interface
|
||||
const USBDescConfig* Config; // configuration descriptor in use
|
||||
const USBDescIface* Ifaces[USB_MAX_INTERFACES]; // interface in use
|
||||
};
|
||||
|
||||
struct USBCombinedPacket {
|
||||
USBPacket* First;
|
||||
QTAILQ_HEAD(packets_head, USBPacket) Packets;
|
||||
IOVector IoVec;
|
||||
};
|
||||
|
||||
/* Structure used to hold information about an active USB packet */
|
||||
struct USBPacket {
|
||||
int Pid; // Packet ID (used to identify the type of packet that is being sent)
|
||||
uint32_t Id; // Paddr of the TD for this packet
|
||||
USBEndpoint* Endpoint; // endpoint this packet is transferred to
|
||||
unsigned int Stream;
|
||||
IOVector IoVec; // used to perform vectored I/O
|
||||
uint64_t Parameter; // control transfers
|
||||
bool ShortNotOK; // the bufferRounding mode of the TD for this packet
|
||||
bool IntReq; // whether or not to generate an interrupt for this packet (DelayInterrupt of the TD is zero)
|
||||
int Status; // USB_RET_* status code
|
||||
int ActualLength; // before copy: offset inside IoVec structs; after copy: number of bytes actually transferred
|
||||
// Internal use by the USB layer
|
||||
USBPacketState State;
|
||||
USBCombinedPacket* Combined;
|
||||
QTAILQ_ENTRY(USBPacket) Queue;
|
||||
QTAILQ_ENTRY(USBPacket) CombinedEntry;
|
||||
};
|
||||
|
||||
struct USBPortOps {
|
||||
std::function<void(USBPort* port)> attach;
|
||||
std::function<void(USBPort* port)> detach;
|
||||
/*
|
||||
* This gets called when a device downstream from the device attached to
|
||||
* the port (attached through a hub) gets detached.
|
||||
*/
|
||||
std::function<void(USBPort* port, XboxDeviceState* child)> child_detach;
|
||||
std::function<void(USBPort* port)> wakeup;
|
||||
/*
|
||||
* Note that port->dev will be different then the device from which
|
||||
* the packet originated when a hub is involved.
|
||||
*/
|
||||
std::function<void(USBPort* port, USBPacket* p)> complete;
|
||||
};
|
||||
|
||||
/* Struct describing the status of a usb port */
|
||||
struct USBPort {
|
||||
XboxDeviceState* Dev; // usb device (if present)
|
||||
USBPortOps* Operations; // functions to call when a port event happens
|
||||
int SpeedMask; // usb speeds supported
|
||||
int HubCount; // number of hubs chained
|
||||
char Path[16]; // the number of the port + 1, used to create a serial number for this device
|
||||
int PortIndex; // internal port index against this HC
|
||||
};
|
||||
|
||||
/* Struct which stores general functions/variables regarding the peripheral */
|
||||
struct USBDeviceClass {
|
||||
std::function<int(XboxDeviceState* dev)> init;
|
||||
|
||||
// Walk (enabled) downstream ports, check for a matching device.
|
||||
// Only hubs implement this.
|
||||
std::function<XboxDeviceState*(XboxDeviceState* dev, uint8_t addr)> find_device;
|
||||
|
||||
// Called when a packet is canceled.
|
||||
std::function<void(XboxDeviceState* dev, USBPacket* p)> cancel_packet;
|
||||
|
||||
// Called when device is destroyed.
|
||||
std::function<void(XboxDeviceState* dev)> handle_destroy;
|
||||
|
||||
// Attach the device
|
||||
std::function<void(XboxDeviceState* dev)> handle_attach;
|
||||
|
||||
// Reset the device
|
||||
std::function<void(XboxDeviceState* dev)> handle_reset;
|
||||
|
||||
// Process control request.
|
||||
// Called from handle_packet().
|
||||
// Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
// then the number of bytes transferred is stored in p->actual_length
|
||||
std::function<void(XboxDeviceState* dev, USBPacket* p, int request, int value,
|
||||
int index, int length, uint8_t *data)> handle_control;
|
||||
|
||||
// Process data transfers (both BULK and ISOC).
|
||||
// Called from handle_packet().
|
||||
// Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
// then the number of bytes transferred is stored in p->actual_length
|
||||
std::function<void(XboxDeviceState* dev, USBPacket* p)> handle_data;
|
||||
|
||||
std::function<void(XboxDeviceState* dev, int Interface,
|
||||
int alt_old, int alt_new)> set_interface;
|
||||
|
||||
// Called when the hcd is done queuing packets for an endpoint, only
|
||||
// necessary for devices which can return USB_RET_ADD_TO_QUEUE.
|
||||
std::function<void(XboxDeviceState* dev, USBEndpoint* ep)> flush_ep_queue;
|
||||
|
||||
// Called by the hcd to let the device know the queue for an endpoint
|
||||
// has been unlinked / stopped. Optional may be NULL.
|
||||
std::function<void(XboxDeviceState* Dev, USBEndpoint* EP)> ep_stopped;
|
||||
|
||||
const char* product_desc; // friendly name of the device
|
||||
const USBDesc* usb_desc; // device descriptor
|
||||
};
|
||||
|
||||
|
||||
/* Abstract class representing a usb peripheral */
|
||||
class UsbPeripheral {
|
||||
protected:
|
||||
USBDeviceClass * m_pPeripheralFuncStruct;
|
||||
XboxDeviceState* m_pDeviceStruct;
|
||||
|
||||
virtual int Init(int pport) = 0;
|
||||
};
|
||||
|
||||
}
|
469
src/core/openxbox/hw/pci/ohci_hub.cpp
Normal file
469
src/core/openxbox/hw/pci/ohci_hub.cpp
Normal file
|
@ -0,0 +1,469 @@
|
|||
/*
|
||||
* 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->Hub.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 <cassert>
|
||||
|
||||
#include "openxbox/log.h"
|
||||
|
||||
#include "ohci.h"
|
||||
#include "ohci_hub.h"
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
USBDescIface::USBDescIface(bool bDefault) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
USBDescIface::~USBDescIface() {
|
||||
delete descs;
|
||||
if (bNumEndpoints != 1) {
|
||||
delete[] eps;
|
||||
return;
|
||||
}
|
||||
delete eps;
|
||||
}
|
||||
|
||||
static const USBDescIface desc_iface_hub(true);
|
||||
|
||||
USBDescDevice::USBDescDevice(bool bDefault) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
USBDescDevice::~USBDescDevice() {
|
||||
delete confs;
|
||||
if (bNumConfigurations != 1) {
|
||||
delete[] confs;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const USBDescDevice desc_device_hub(true);
|
||||
|
||||
static USBDescStrings desc_strings = { nullptr, "Cxbx-Reloaded", "Cxbx-Reloaded USB Hub", "314159" };
|
||||
|
||||
USBDesc::USBDesc(bool bDefault) {
|
||||
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;
|
||||
str = desc_strings;
|
||||
}
|
||||
}
|
||||
|
||||
static const USBDesc desc_hub(true);
|
||||
|
||||
int Hub::Init(int pport) {
|
||||
ClassInitFn();
|
||||
UsbEpInit();
|
||||
int rc = UsbClaimPort(pport);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
rc = m_UsbDev->USB_DeviceInit(m_pDeviceStruct);
|
||||
if (rc != 0) {
|
||||
UsbReleasePort(m_pDeviceStruct);
|
||||
return rc;
|
||||
}
|
||||
m_UsbDev->USB_DeviceAttach(m_pDeviceStruct);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Hub::~Hub() {
|
||||
delete m_pPeripheralFuncStruct;
|
||||
delete m_HubState->ports[0].port.Operations;
|
||||
delete m_HubState;
|
||||
m_pPeripheralFuncStruct = nullptr;
|
||||
m_pDeviceStruct = nullptr;
|
||||
}
|
||||
|
||||
void Hub::ClassInitFn() {
|
||||
m_pPeripheralFuncStruct = new USBDeviceClass();
|
||||
m_HubState = new USBHubState();
|
||||
m_pDeviceStruct = &m_HubState->dev;
|
||||
|
||||
m_pDeviceStruct->ProductDesc = "Cxbx-Reloaded USB Hub";
|
||||
QLIST_INIT(&m_pDeviceStruct->Strings);
|
||||
m_pDeviceStruct->klass = m_pPeripheralFuncStruct;
|
||||
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
m_pPeripheralFuncStruct->init = std::bind(&Hub::UsbHub_Initfn, this, _1);
|
||||
m_pPeripheralFuncStruct->find_device = std::bind(&Hub::UsbHub_FindDevice, this, _1, _2);
|
||||
m_pPeripheralFuncStruct->handle_reset = std::bind(&Hub::UsbHub_HandleReset, this);
|
||||
m_pPeripheralFuncStruct->handle_control = std::bind(&Hub::UsbHub_HandleControl, this, _1, _2, _3, _4, _5, _6, _7);
|
||||
m_pPeripheralFuncStruct->handle_data = std::bind(&Hub::UsbHub_HandleData, this, _1, _2);
|
||||
m_pPeripheralFuncStruct->handle_destroy = std::bind(&Hub::UsbHub_HandleDestroy, this, _1);
|
||||
m_pPeripheralFuncStruct->product_desc = m_pDeviceStruct->ProductDesc.c_str();
|
||||
m_pPeripheralFuncStruct->usb_desc = &desc_hub;
|
||||
}
|
||||
}
|
||||
|
||||
void Hub::UsbEpInit() {
|
||||
UsbEpReset();
|
||||
QTAILQ_INIT(&m_pDeviceStruct->EP_ctl.Queue);
|
||||
for (int ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
|
||||
QTAILQ_INIT(&m_pDeviceStruct->EP_in[ep].Queue);
|
||||
QTAILQ_INIT(&m_pDeviceStruct->EP_out[ep].Queue);
|
||||
}
|
||||
}
|
||||
|
||||
void Hub::UsbEpReset() {
|
||||
m_pDeviceStruct->EP_ctl.Num = 0;
|
||||
m_pDeviceStruct->EP_ctl.Type = USB_ENDPOINT_XFER_CONTROL;
|
||||
m_pDeviceStruct->EP_ctl.IfNum = 0;
|
||||
m_pDeviceStruct->EP_ctl.MaxPacketSize = 64;
|
||||
m_pDeviceStruct->EP_ctl.Dev = m_pDeviceStruct;
|
||||
m_pDeviceStruct->EP_ctl.Pipeline = false;
|
||||
for (int ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
|
||||
m_pDeviceStruct->EP_in[ep].Num = ep + 1;
|
||||
m_pDeviceStruct->EP_out[ep].Num = ep + 1;
|
||||
m_pDeviceStruct->EP_in[ep].pid = USB_TOKEN_IN;
|
||||
m_pDeviceStruct->EP_out[ep].pid = USB_TOKEN_OUT;
|
||||
m_pDeviceStruct->EP_in[ep].Type = USB_ENDPOINT_XFER_INVALID;
|
||||
m_pDeviceStruct->EP_out[ep].Type = USB_ENDPOINT_XFER_INVALID;
|
||||
m_pDeviceStruct->EP_in[ep].IfNum = USB_INTERFACE_INVALID;
|
||||
m_pDeviceStruct->EP_out[ep].IfNum = USB_INTERFACE_INVALID;
|
||||
m_pDeviceStruct->EP_in[ep].MaxPacketSize = 0;
|
||||
m_pDeviceStruct->EP_out[ep].MaxPacketSize = 0;
|
||||
m_pDeviceStruct->EP_in[ep].Dev = m_pDeviceStruct;
|
||||
m_pDeviceStruct->EP_out[ep].Dev = m_pDeviceStruct;
|
||||
m_pDeviceStruct->EP_in[ep].Pipeline = false;
|
||||
m_pDeviceStruct->EP_out[ep].Pipeline = false;
|
||||
}
|
||||
}
|
||||
|
||||
int Hub::UsbClaimPort(int pport) {
|
||||
int usb_port;
|
||||
|
||||
assert(m_pDeviceStruct->Port == nullptr);
|
||||
|
||||
if (pport > 4 || pport < 1) { return -1; };
|
||||
|
||||
usb_port = PlayerToUsbArray[pport];
|
||||
if (usb_port > 2) {
|
||||
m_UsbDev = g_USB0; // FIXME: how to retrieve these?
|
||||
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 3, m_pDeviceStruct);
|
||||
}
|
||||
else {
|
||||
m_UsbDev = g_USB1; // FIXME: how to retrieve these?
|
||||
m_UsbDev->m_HostController->OHCI_AssignUsbPortStruct(usb_port - 1, m_pDeviceStruct);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Hub::UsbReleasePort(XboxDeviceState* dev) {
|
||||
USBPort * port = dev->Port;
|
||||
|
||||
assert(port != nullptr);
|
||||
|
||||
port->Dev = nullptr;
|
||||
dev->Port = nullptr;
|
||||
}
|
||||
|
||||
int Hub::UsbHub_Initfn(XboxDeviceState* dev) {
|
||||
USBHubPort* port;
|
||||
USBPortOps* ops;
|
||||
int i;
|
||||
|
||||
if (dev->Port->HubCount == 5) {
|
||||
log_debug("Hub: chain too deep");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CreateSerial(dev);
|
||||
UsbDescInit(dev);
|
||||
m_HubState->intr = m_UsbDev->USB_GetEP(dev, USB_TOKEN_IN, 1);
|
||||
|
||||
ops = new USBPortOps();
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
ops->attach = std::bind(&Hub::UsbHub_Attach, this, _1);
|
||||
ops->detach = std::bind(&Hub::UsbHub_Detach, this, _1);
|
||||
ops->child_detach = std::bind(&Hub::UsbHub_ChildDetach, this, _1, _2);
|
||||
ops->wakeup = std::bind(&Hub::UsbHub_Wakeup, this, _1);
|
||||
ops->complete = std::bind(&Hub::UsbHub_Complete, this, _1, _2);
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_PORTS; i++) {
|
||||
port = &m_HubState->ports[i];
|
||||
m_UsbDev->USB_RegisterPort(&port->port, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL, ops);
|
||||
m_UsbDev->USB_PortLocation(&port->port, dev->Port, i + 1);
|
||||
}
|
||||
UsbHub_HandleReset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Hub::UsbHub_HandleReset() {
|
||||
USBHubPort* port;
|
||||
|
||||
for (int i = 0; i < NUM_PORTS; i++) {
|
||||
port = m_HubState->ports + i;
|
||||
port->wPortStatus = PORT_STAT_POWER;
|
||||
port->wPortChange = 0;
|
||||
if (port->port.Dev && port->port.Dev->Attached) {
|
||||
port->wPortStatus |= PORT_STAT_CONNECTION;
|
||||
port->wPortChange |= PORT_STAT_C_CONNECTION;
|
||||
if (port->port.Dev->Speed == USB_SPEED_LOW) {
|
||||
port->wPortStatus |= PORT_STAT_LOW_SPEED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* From XQEMU:
|
||||
* This function creates a serial number for a usb device.
|
||||
* The serial number should:
|
||||
* (a) Be unique within the emulator.
|
||||
* (b) Be constant, so you don't get a new one each
|
||||
* time the guest is started.
|
||||
* So we are using the physical location to generate a serial number
|
||||
* from it. It has three pieces: First a fixed, device-specific
|
||||
* prefix. Second the device path of the host controller (which is
|
||||
* the pci address in most cases). Third the physical port path.
|
||||
* Results in serial numbers like this: "314159-0000:00:1d.7-3".
|
||||
*/
|
||||
void Hub::CreateSerial(XboxDeviceState* dev) {
|
||||
const USBDesc* desc = GetUsbDeviceDesc(dev);
|
||||
int index = desc->id.iSerialNumber;
|
||||
USBDescString* s;
|
||||
char serial[64];
|
||||
char* path;
|
||||
int dst;
|
||||
|
||||
assert(index != 0 && desc->str[index] != NULL);
|
||||
dst = std::snprintf(serial, sizeof(serial), "%s", desc->str[index]);
|
||||
dst += std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", m_UsbDev->m_PciPath);
|
||||
dst += std::snprintf(serial + dst, sizeof(serial) - dst, "-%s", dev->Port->Path);
|
||||
|
||||
QLIST_FOREACH(s, &dev->Strings, next) {
|
||||
if (s->index == index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == nullptr) {
|
||||
s = new USBDescString;
|
||||
s->index = index;
|
||||
QLIST_INSERT_HEAD(&dev->Strings, s, next);
|
||||
}
|
||||
|
||||
s->str = serial;
|
||||
}
|
||||
|
||||
const USBDesc* Hub::GetUsbDeviceDesc(XboxDeviceState* dev) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (dev->UsbDesc) {
|
||||
return dev->UsbDesc;
|
||||
}
|
||||
return klass->usb_desc;
|
||||
}
|
||||
|
||||
void Hub::UsbDescInit(XboxDeviceState* dev) {
|
||||
const USBDesc* desc = GetUsbDeviceDesc(dev);
|
||||
|
||||
assert(desc != NULL);
|
||||
dev->Speed = USB_SPEED_FULL;
|
||||
dev->SpeedMask = 0;
|
||||
if (desc->full) {
|
||||
dev->SpeedMask |= USB_SPEED_MASK_FULL;
|
||||
}
|
||||
UsbDescSetDefaults(dev);
|
||||
}
|
||||
|
||||
void Hub::UsbDescSetDefaults(XboxDeviceState* dev) {
|
||||
const USBDesc *desc = GetUsbDeviceDesc(dev);
|
||||
|
||||
assert(desc != NULL);
|
||||
switch (dev->Speed) {
|
||||
case USB_SPEED_LOW:
|
||||
case USB_SPEED_FULL:
|
||||
{
|
||||
dev->Device = desc->full;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
log_warning("Unknown speed parameter %d set in %s", dev->ProductDesc.c_str());
|
||||
}
|
||||
UsbDescSetConfig(dev, 0);
|
||||
}
|
||||
|
||||
int Hub::UsbDescSetConfig(XboxDeviceState* dev, int value) {
|
||||
int i;
|
||||
|
||||
if (value == 0) { // default configuration
|
||||
dev->Configuration = 0;
|
||||
dev->NumInterfaces = 0;
|
||||
dev->Config = nullptr;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < dev->Device->bNumConfigurations; i++) { // select the configuration specified
|
||||
if (dev->Device->confs[i].bConfigurationValue == value) {
|
||||
dev->Configuration = value;
|
||||
dev->NumInterfaces = dev->Device->confs[i].bNumInterfaces;
|
||||
dev->Config = dev->Device->confs + i;
|
||||
assert(dev->NumInterfaces <= USB_MAX_INTERFACES);
|
||||
}
|
||||
}
|
||||
if (i < dev->Device->bNumConfigurations) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dev->NumInterfaces; i++) { // setup all interfaces for the selected configuration
|
||||
UsbDescSetInterface(dev, i, 0);
|
||||
}
|
||||
for (; i < USB_MAX_INTERFACES; i++) { // null the remaining interfaces
|
||||
dev->AltSetting[i] = 0;
|
||||
dev->Ifaces[i] = nullptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Hub::UsbDescSetInterface(XboxDeviceState* dev, int index, int value) {
|
||||
const USBDescIface* iface;
|
||||
int old;
|
||||
|
||||
iface = UsbDescFindInterface(dev, index, value);
|
||||
if (iface == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
old = dev->AltSetting[index];
|
||||
dev->AltSetting[index] = value;
|
||||
dev->Ifaces[index] = iface;
|
||||
UsbDescEpInit(dev);
|
||||
|
||||
if (old != value) {
|
||||
m_UsbDev->USB_DeviceSetInterface(dev, index, old, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const USBDescIface* Hub::UsbDescFindInterface(XboxDeviceState* dev, int nif, int alt) {
|
||||
const USBDescIface* iface;
|
||||
int i;
|
||||
|
||||
if (!dev->Config) { // no configuration descriptor here, nothing to search
|
||||
return nullptr;
|
||||
}
|
||||
for (i = 0; i < dev->Config->nif; i++) { // find the desired interface
|
||||
iface = &dev->Config->ifs[i];
|
||||
if (iface->bInterfaceNumber == nif &&
|
||||
iface->bAlternateSetting == alt) {
|
||||
return iface;
|
||||
}
|
||||
}
|
||||
return nullptr; // not found
|
||||
}
|
||||
|
||||
void Hub::UsbDescEpInit(XboxDeviceState* dev) {
|
||||
const USBDescIface *iface;
|
||||
int i, e, pid, ep;
|
||||
|
||||
UsbEpInit(); // reset endpoints (because we changed descriptors in use?)
|
||||
for (i = 0; i < dev->NumInterfaces; i++) {
|
||||
iface = dev->Ifaces[i];
|
||||
if (iface == nullptr) {
|
||||
continue;
|
||||
}
|
||||
for (e = 0; e < iface->bNumEndpoints; e++) {
|
||||
// From the standard:
|
||||
// "bEndpointAddress:
|
||||
// Bit 3...0: The endpoint number
|
||||
// Bit 6...4: Reserved, reset to zero
|
||||
// Bit 7: Direction -> 0 = OUT endpoint, 1 = IN endpoint
|
||||
// bmAttributes:
|
||||
// Bit 1..0: Transfer Type
|
||||
// 00 = Control, 01 = Isochronous, 10 = Bulk, 11 = Interrupt. All other bits are reserved"
|
||||
pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||
ep = iface->eps[e].bEndpointAddress & 0xF;
|
||||
m_UsbDev->USB_EPsetType(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
|
||||
m_UsbDev->USB_EPsetIfnum(dev, pid, ep, iface->bInterfaceNumber);
|
||||
m_UsbDev->USB_EPsetMaxPacketSize(dev, pid, ep, iface->eps[e].wMaxPacketSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
143
src/core/openxbox/hw/pci/ohci_hub.h
Normal file
143
src/core/openxbox/hw/pci/ohci_hub.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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->Hub.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
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ohci_common.h"
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
#define NUM_PORTS 8
|
||||
|
||||
#define PORT_STAT_CONNECTION 0x0001
|
||||
#define PORT_STAT_ENABLE 0x0002
|
||||
#define PORT_STAT_SUSPEND 0x0004
|
||||
#define PORT_STAT_OVERCURRENT 0x0008
|
||||
#define PORT_STAT_RESET 0x0010
|
||||
#define PORT_STAT_POWER 0x0100
|
||||
#define PORT_STAT_LOW_SPEED 0x0200
|
||||
|
||||
#define PORT_STAT_C_CONNECTION 0x0001
|
||||
#define PORT_STAT_C_ENABLE 0x0002
|
||||
#define PORT_STAT_C_SUSPEND 0x0004
|
||||
#define PORT_STAT_C_OVERCURRENT 0x0008
|
||||
#define PORT_STAT_C_RESET 0x0010
|
||||
|
||||
|
||||
/* same as Linux kernel root hubs */
|
||||
typedef enum {
|
||||
STR_MANUFACTURER = 1,
|
||||
STR_PRODUCT,
|
||||
STR_SERIALNUMBER,
|
||||
};
|
||||
|
||||
struct USBHubPort {
|
||||
USBPort port; // downstream port status
|
||||
uint16_t wPortStatus; // Port Status Field, in accordance with the standard
|
||||
uint16_t wPortChange; // Port Change Field, in accordance with the standard
|
||||
};
|
||||
|
||||
struct USBHubState {
|
||||
XboxDeviceState dev; // hub device status
|
||||
USBEndpoint* intr; // interrupt endpoint of the hub
|
||||
USBHubPort ports[NUM_PORTS]; // downstream ports of the hub
|
||||
};
|
||||
|
||||
/* Class which implements a usb hub */
|
||||
class Hub final : public UsbPeripheral {
|
||||
public:
|
||||
// initialize this peripheral
|
||||
int Init(int pport) override;
|
||||
// destructor
|
||||
~Hub();
|
||||
|
||||
|
||||
private:
|
||||
// usb device this hub is attached to
|
||||
USBPCIDevice* m_UsbDev = nullptr;
|
||||
// hub state
|
||||
USBHubState* m_HubState = nullptr;
|
||||
|
||||
// initialize various member variables/functions
|
||||
void ClassInitFn();
|
||||
// see USBDeviceClass for comments about these functions
|
||||
int UsbHub_Initfn(XboxDeviceState* dev);
|
||||
XboxDeviceState* UsbHub_FindDevice(XboxDeviceState* dev, uint8_t addr);
|
||||
void UsbHub_HandleReset();
|
||||
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);
|
||||
// see USBPortOps struct for info
|
||||
void UsbHub_Attach(USBPort* port1);
|
||||
void UsbHub_Detach(USBPort* port1);
|
||||
void UsbHub_ChildDetach(USBPort* port1, XboxDeviceState* child);
|
||||
void UsbHub_Wakeup(USBPort* port1);
|
||||
void UsbHub_Complete(USBPort* port, USBPacket* packet);
|
||||
// TODO: perhaps these can be put in UsbPeripheral or USBDevice...
|
||||
// initialize the endpoints of this peripheral
|
||||
void UsbEpInit();
|
||||
// reset all endpoints of this peripheral
|
||||
void UsbEpReset();
|
||||
// reserve a usb port for this hub
|
||||
int UsbClaimPort(int port);
|
||||
//
|
||||
void UsbReleasePort(XboxDeviceState* dev);
|
||||
// get device descriptor
|
||||
const USBDesc* GetUsbDeviceDesc(XboxDeviceState* dev);
|
||||
// create a serial number for the device
|
||||
void CreateSerial(XboxDeviceState* dev);
|
||||
// start descriptors initialization
|
||||
void UsbDescInit(XboxDeviceState* dev);
|
||||
// set the descriptors to use for this device
|
||||
void UsbDescSetDefaults(XboxDeviceState* dev);
|
||||
// set the configuration to use
|
||||
int UsbDescSetConfig(XboxDeviceState* dev, int value);
|
||||
// set the interface to use
|
||||
int UsbDescSetInterface(XboxDeviceState* dev, int index, int value);
|
||||
// find the interface to use
|
||||
const USBDescIface* UsbDescFindInterface(XboxDeviceState* dev, int nif, int alt);
|
||||
// setup endpoints and their descriptors
|
||||
void UsbDescEpInit(XboxDeviceState* dev);
|
||||
};
|
||||
|
||||
extern Hub* g_HubObjArray[4];
|
||||
|
||||
}
|
|
@ -37,32 +37,28 @@
|
|||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
|
||||
#include "openxbox/log.h"
|
||||
|
||||
#include "usb_pci.h"
|
||||
#include "ohci.h"
|
||||
#include "openxbox/log.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
#define USB_ENDPOINT_XFER_CONTROL 0
|
||||
#define USB_ENDPOINT_XFER_ISOC 1
|
||||
#define USB_ENDPOINT_XFER_BULK 2
|
||||
#define USB_ENDPOINT_XFER_INT 3
|
||||
#define USB_ENDPOINT_XFER_INVALID 255
|
||||
|
||||
#define USB_DIR_OUT 0
|
||||
#define USB_DIR_IN 0x80
|
||||
|
||||
#define SETUP_STATE_IDLE 0
|
||||
#define SETUP_STATE_SETUP 1
|
||||
#define SETUP_STATE_DATA 2
|
||||
#define SETUP_STATE_ACK 3
|
||||
#define SETUP_STATE_PARAM 4
|
||||
|
||||
USBPCIDevice::USBPCIDevice(uint16_t vendorID, uint16_t deviceID, uint8_t revisionID, uint8_t irqn)
|
||||
USBPCIDevice::USBPCIDevice(uint16_t vendorID, uint16_t deviceID, uint8_t revisionID, uint8_t irqn, Cpu* cpu)
|
||||
: PCIDevice(PCI_HEADER_TYPE_NORMAL, vendorID, deviceID, revisionID,
|
||||
0x0c, 0x03, 0x10) // USB OHCI
|
||||
, m_irqn(irqn)
|
||||
, m_cpu(cpu)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -74,7 +70,14 @@ USBPCIDevice::~USBPCIDevice() {
|
|||
void USBPCIDevice::Init() {
|
||||
RegisterBAR(0, 0x1000, PCI_BAR_TYPE_MEMORY); // 0xFED00000 - 0xFED00FFF and 0xFED08000 - 0xFED08FFF
|
||||
|
||||
m_HostController = new OHCI(m_irqn, this);
|
||||
if (m_irqn == 1) {
|
||||
m_PciPath = "pci.0:02.0";
|
||||
}
|
||||
else {
|
||||
m_PciPath = "pci.0:03.0";
|
||||
}
|
||||
|
||||
m_HostController = new OHCI(m_cpu, m_irqn, this);
|
||||
}
|
||||
|
||||
void USBPCIDevice::Reset() {
|
||||
|
@ -97,23 +100,15 @@ void USBPCIDevice::PCIMMIOWrite(int barIndex, uint32_t addr, uint32_t value, uin
|
|||
}
|
||||
|
||||
|
||||
void USBPCIDevice::USB_RegisterPort(USBPort* Port, int Index, int SpeedMask) {
|
||||
void USBPCIDevice::USB_RegisterPort(USBPort* Port, int Index, int SpeedMask, USBPortOps* Ops) {
|
||||
Port->PortIndex = Index;
|
||||
Port->SpeedMask = SpeedMask;
|
||||
Port->HubCount = 0;
|
||||
std::snprintf(Port->Path, sizeof(Port->Path), "%d", Index + 1);
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceEPstopped(XboxDevice* Dev, USBEndpoint* EP) {
|
||||
// This seems to be a nop in XQEMU since it doesn't assign the EP_Stopped function (it's nullptr)
|
||||
USBDeviceClass* klass = USB_DEVICE_GET_CLASS(Dev);
|
||||
if (klass->EP_Stopped) {
|
||||
klass->EP_Stopped(Dev, EP);
|
||||
}
|
||||
Port->Operations = Ops;
|
||||
USB_PortLocation(Port, nullptr, Index + 1);
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_PortReset(USBPort* Port) {
|
||||
XboxDevice* dev = Port->Dev;
|
||||
XboxDeviceState* dev = Port->Dev;
|
||||
|
||||
assert(dev != nullptr);
|
||||
USB_Detach(Port);
|
||||
|
@ -122,7 +117,7 @@ void USBPCIDevice::USB_PortReset(USBPort* Port) {
|
|||
}
|
||||
|
||||
void USBPCIDevice::USB_Detach(USBPort* Port) {
|
||||
XboxDevice* dev = Port->Dev;
|
||||
XboxDeviceState* dev = Port->Dev;
|
||||
|
||||
assert(dev != nullptr);
|
||||
assert(dev->State != USB_STATE_NOTATTACHED);
|
||||
|
@ -131,17 +126,17 @@ void USBPCIDevice::USB_Detach(USBPort* Port) {
|
|||
}
|
||||
|
||||
void USBPCIDevice::USB_Attach(USBPort* Port) {
|
||||
XboxDevice *dev = Port->Dev;
|
||||
XboxDeviceState* dev = Port->Dev;
|
||||
|
||||
assert(dev != nullptr);
|
||||
assert(dev->Attached);
|
||||
assert(dev->State == USB_STATE_NOTATTACHED);
|
||||
m_HostController->OHCI_Attach(Port);
|
||||
Port->Operations->attach(Port);
|
||||
dev->State = USB_STATE_ATTACHED;
|
||||
usb_device_handle_attach(dev);
|
||||
USB_DeviceHandleAttach(dev);
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceReset(XboxDevice* dev) {
|
||||
void USBPCIDevice::USB_DeviceReset(XboxDeviceState* dev) {
|
||||
if (dev == nullptr || !dev->Attached) {
|
||||
return;
|
||||
}
|
||||
|
@ -152,8 +147,8 @@ void USBPCIDevice::USB_DeviceReset(XboxDevice* dev) {
|
|||
usb_device_handle_reset(dev);
|
||||
}
|
||||
|
||||
XboxDevice* USBPCIDevice::USB_FindDevice(USBPort* Port, uint8_t Addr) {
|
||||
XboxDevice* dev = Port->Dev;
|
||||
XboxDeviceState* USBPCIDevice::USB_FindDevice(USBPort* Port, uint8_t Addr) {
|
||||
XboxDeviceState* dev = Port->Dev;
|
||||
|
||||
if (dev == nullptr || !dev->Attached || dev->State != USB_STATE_DEFAULT) {
|
||||
return nullptr;
|
||||
|
@ -165,16 +160,7 @@ XboxDevice* USBPCIDevice::USB_FindDevice(USBPort* Port, uint8_t Addr) {
|
|||
return USB_DeviceFindDevice(dev, Addr);
|
||||
}
|
||||
|
||||
XboxDevice* USBPCIDevice::USB_DeviceFindDevice(XboxDevice* Dev, uint8_t Addr) {
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(Dev);
|
||||
if (klass->find_device) {
|
||||
return klass->find_device(Dev, Addr); // TODO: usb_hub_find_device
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
USBEndpoint* USBPCIDevice::USB_GetEP(XboxDevice* Dev, int Pid, int Ep) {
|
||||
USBEndpoint* USBPCIDevice::USB_GetEP(XboxDeviceState* Dev, int Pid, int Ep) {
|
||||
USBEndpoint* eps;
|
||||
|
||||
if (Dev == nullptr) {
|
||||
|
@ -216,7 +202,7 @@ void USBPCIDevice::USB_PacketAddBuffer(USBPacket* p, void* ptr, size_t len) {
|
|||
IoVecAdd(&p->IoVec, ptr, len);
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_HandlePacket(XboxDevice* dev, USBPacket* p) {
|
||||
void USBPCIDevice::USB_HandlePacket(XboxDeviceState* dev, USBPacket* p) {
|
||||
if (dev == nullptr) {
|
||||
p->Status = USB_RET_NODEV;
|
||||
return;
|
||||
|
@ -277,7 +263,7 @@ void USBPCIDevice::USB_PacketCheckState(USBPacket* p, USBPacketState expected) {
|
|||
}
|
||||
|
||||
void USBPCIDevice::USB_ProcessOne(USBPacket* p) {
|
||||
XboxDevice* dev = p->Endpoint->Dev;
|
||||
XboxDeviceState* dev = p->Endpoint->Dev;
|
||||
|
||||
// Handlers expect status to be initialized to USB_RET_SUCCESS, but it
|
||||
// can be USB_RET_NAK here from a previous usb_process_one() call,
|
||||
|
@ -311,7 +297,7 @@ void USBPCIDevice::USB_ProcessOne(USBPacket* p) {
|
|||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DoParameter(XboxDevice* s, USBPacket* p) {
|
||||
void USBPCIDevice::USB_DoParameter(XboxDeviceState* s, USBPacket* p) {
|
||||
int i, request, value, index;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
|
@ -350,7 +336,7 @@ void USBPCIDevice::USB_DoParameter(XboxDevice* s, USBPacket* p) {
|
|||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DoTokenSetup(XboxDevice* s, USBPacket* p) {
|
||||
void USBPCIDevice::USB_DoTokenSetup(XboxDeviceState* s, USBPacket* p) {
|
||||
int request, value, index;
|
||||
|
||||
// From the standard "Every Setup packet has eight bytes."
|
||||
|
@ -407,7 +393,7 @@ void USBPCIDevice::USB_DoTokenSetup(XboxDevice* s, USBPacket* p) {
|
|||
p->ActualLength = 8;
|
||||
}
|
||||
|
||||
void USBPCIDevice::DoTokenIn(XboxDevice* s, USBPacket* p) {
|
||||
void USBPCIDevice::DoTokenIn(XboxDeviceState* s, USBPacket* p) {
|
||||
int request, value, index;
|
||||
|
||||
assert(p->Endpoint->Num == 0);
|
||||
|
@ -450,7 +436,7 @@ void USBPCIDevice::DoTokenIn(XboxDevice* s, USBPacket* p) {
|
|||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::DoTokenOut(XboxDevice* s, USBPacket* p) {
|
||||
void USBPCIDevice::DoTokenOut(XboxDeviceState* s, USBPacket* p) {
|
||||
assert(p->Endpoint->Num == 0);
|
||||
|
||||
switch (s->SetupState) {
|
||||
|
@ -506,31 +492,87 @@ void USBPCIDevice::USB_PacketCopy(USBPacket* p, void* ptr, size_t bytes) {
|
|||
p->ActualLength += bytes;
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceHandleControl(XboxDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) {
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_control) {
|
||||
klass->handle_control(dev, p, request, value, index, length, data); // TODO: usb_hub_handle_control
|
||||
int USBPCIDevice::USB_DeviceInit(XboxDeviceState* dev) {
|
||||
USBDeviceClass * klass = dev->klass;
|
||||
if (klass->init) {
|
||||
return klass->init(dev);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceHandleData(XboxDevice* dev, USBPacket* p) {
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->handle_data) {
|
||||
klass->handle_data(dev, p); // TODO: usb_hub_handle_data
|
||||
XboxDeviceState* USBPCIDevice::USB_DeviceFindDevice(XboxDeviceState* dev, uint8_t Addr) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->find_device) {
|
||||
return klass->find_device(dev, Addr);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceFlushEPqueue(XboxDevice* dev, USBEndpoint* ep) {
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
if (klass->flush_ep_queue) {
|
||||
klass->flush_ep_queue(dev, ep); // TODO: it's nullptr in XQEMU...
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceCancelPacket(XboxDevice* dev, USBPacket* p) {
|
||||
USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
|
||||
void USBPCIDevice::USB_DeviceCancelPacket(XboxDeviceState* dev, USBPacket* p) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->cancel_packet) {
|
||||
klass->cancel_packet(dev, p); // TODO: it's nullptr in XQEMU...
|
||||
klass->cancel_packet(dev, p);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceHandleDestroy(XboxDeviceState* dev) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->handle_destroy) {
|
||||
klass->handle_destroy(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceHandleAttach(XboxDeviceState* dev) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->handle_attach) {
|
||||
klass->handle_attach(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceHandleReset(XboxDeviceState* dev) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->handle_reset) {
|
||||
klass->handle_reset(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceHandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->handle_control) {
|
||||
klass->handle_control(dev, p, request, value, index, length, data);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceHandleData(XboxDeviceState* dev, USBPacket* p) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->handle_data) {
|
||||
klass->handle_data(dev, p);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceSetInterface(XboxDeviceState* dev, int iface, int alt_old, int alt_new) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->set_interface) {
|
||||
klass->set_interface(dev, iface, alt_old, alt_new);
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceFlushEPqueue(XboxDeviceState* dev, USBEndpoint* ep) {
|
||||
USBDeviceClass *klass = dev->klass;
|
||||
if (klass->flush_ep_queue) {
|
||||
klass->flush_ep_queue(dev, ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void USBPCIDevice::USB_DeviceEPstopped(XboxDeviceState* dev, USBEndpoint* EP) {
|
||||
USBDeviceClass* klass = dev->klass;
|
||||
if (klass->ep_stopped) {
|
||||
klass->ep_stopped(dev, EP);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -544,5 +586,44 @@ void USBPCIDevice::USB_CancelPacket(USBPacket* p) {
|
|||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_EPsetType(XboxDeviceState* dev, int pid, int ep, uint8_t type) {
|
||||
USBEndpoint* uep = USB_GetEP(dev, pid, ep);
|
||||
uep->Type = type;
|
||||
}
|
||||
|
||||
uint8_t USBPCIDevice::USB_EPsetIfnum(XboxDeviceState* dev, int pid, int ep, uint8_t ifnum) {
|
||||
USBEndpoint* uep = USB_GetEP(dev, pid, ep);
|
||||
uep->IfNum = ifnum;
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_EPsetMaxPacketSize(XboxDeviceState* dev, int pid, int ep, uint16_t raw) {
|
||||
USBEndpoint* uep = USB_GetEP(dev, pid, ep);
|
||||
|
||||
// Dropped from XQEMU the calculation max_packet_size = size * microframes since that's only true
|
||||
// for high speed (usb 2.0) devices
|
||||
uep->MaxPacketSize = raw & 0x7FF;
|
||||
}
|
||||
|
||||
void 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;
|
||||
}
|
||||
else {
|
||||
std::snprintf(downstream->Path, sizeof(downstream->Path), "%d", portnr);
|
||||
downstream->HubCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void USBPCIDevice::USB_DeviceAttach(XboxDeviceState* dev) {
|
||||
USBPort * port = dev->Port;
|
||||
|
||||
assert(port != nullptr);
|
||||
assert(!dev->Attached);
|
||||
|
||||
dev->Attached++;
|
||||
USB_Attach(port);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,28 +44,11 @@
|
|||
|
||||
#include "../defs.h"
|
||||
#include "pci.h"
|
||||
#include "openxbox/queue.h"
|
||||
#include "openxbox/iovec.h"
|
||||
#include "ohci_common.h"
|
||||
#include "openxbox/cpu.h"
|
||||
|
||||
namespace openxbox {
|
||||
|
||||
#define USB_MAX_ENDPOINTS 15
|
||||
#define USB_MAX_INTERFACES 16
|
||||
|
||||
#define USB_STATE_NOTATTACHED 0
|
||||
#define USB_STATE_ATTACHED 1
|
||||
#define USB_STATE_DEFAULT 2
|
||||
|
||||
typedef enum USBPacketState {
|
||||
USB_PACKET_UNDEFINED = 0,
|
||||
USB_PACKET_SETUP,
|
||||
USB_PACKET_QUEUED,
|
||||
USB_PACKET_ASYNC,
|
||||
USB_PACKET_COMPLETE,
|
||||
USB_PACKET_CANCELED,
|
||||
}
|
||||
USBPacketState;
|
||||
|
||||
typedef enum USBDeviceFlags {
|
||||
USB_DEV_FLAG_FULL_PATH,
|
||||
USB_DEV_FLAG_IS_HOST,
|
||||
|
@ -74,160 +57,14 @@ typedef enum USBDeviceFlags {
|
|||
}
|
||||
USBDeviceFlags;
|
||||
|
||||
typedef struct _USBPacket USBPacket;
|
||||
typedef struct _XboxDevice XboxDevice;
|
||||
|
||||
/* USB endpoint */
|
||||
typedef struct _USBEndpoint {
|
||||
uint8_t Num; // endpoint number
|
||||
uint8_t pid;
|
||||
uint8_t Type; // the type of this endpoint
|
||||
uint8_t ifnum;
|
||||
int max_packet_size;
|
||||
bool Pipeline;
|
||||
bool Halted; // indicates that the endpoint is halted
|
||||
XboxDevice* Dev; // device this endpoint belongs to
|
||||
QTAILQ_HEAD(, _USBPacket) Queue; // queue of packets to this endpoint
|
||||
}
|
||||
USBEndpoint;
|
||||
|
||||
/* definition of an Xbox usb device */
|
||||
typedef struct _XboxDevice {
|
||||
DeviceState qdev;
|
||||
USBPort *port;
|
||||
char *port_path;
|
||||
char *serial;
|
||||
void *opaque;
|
||||
uint32_t flags;
|
||||
|
||||
// Actual connected speed
|
||||
int speed;
|
||||
// Supported speeds, not in info because it may be variable (hostdevs)
|
||||
int speedmask;
|
||||
uint8_t Addr; // device function address
|
||||
char product_desc[32];
|
||||
int auto_attach;
|
||||
int Attached; // device is attached
|
||||
|
||||
int32_t State; // current state of device
|
||||
uint8_t SetupBuffer[8]; // holds the IoVec structs copied (control transfers only?)
|
||||
uint8_t data_buf[4096];
|
||||
int32_t RemoteWakeup; // wakeup flag
|
||||
int32_t SetupState; // result of a setup tken processing operation
|
||||
int32_t SetupLength; // number of bytes to transfer as specified by a setup token
|
||||
int32_t SetupIndex; // index of the parameter in a setup token?
|
||||
|
||||
USBEndpoint EP_ctl; // endpoints for SETUP tokens
|
||||
USBEndpoint EP_in[USB_MAX_ENDPOINTS]; // endpoints for OUT tokens
|
||||
USBEndpoint EP_out[USB_MAX_ENDPOINTS]; // endpoints for IN tokens
|
||||
|
||||
//QLIST_HEAD(, USBDescString) strings;
|
||||
const USBDesc *usb_desc; // Overrides class usb_desc if not NULL
|
||||
const USBDescDevice *device;
|
||||
|
||||
int configuration;
|
||||
int ninterfaces;
|
||||
int altsetting[USB_MAX_INTERFACES];
|
||||
const USBDescConfig *config;
|
||||
const USBDescIface *ifaces[USB_MAX_INTERFACES];
|
||||
}
|
||||
XboxDevice;
|
||||
|
||||
// ergo720: this could be merged in the OHCI or USBDevice class if possible
|
||||
typedef struct USBDeviceClass {
|
||||
DeviceClass parent_class;
|
||||
|
||||
int(*init)(USBDev *dev);
|
||||
|
||||
// Walk (enabled) downstream ports, check for a matching device.
|
||||
// Only hubs implement this.
|
||||
USBDev *(*find_device)(USBDev *dev, uint8_t addr);
|
||||
|
||||
// Called when a packet is canceled.
|
||||
void(*cancel_packet)(USBDev *dev, USBPacket *p);
|
||||
|
||||
// Called when device is destroyed.
|
||||
void(*handle_destroy)(USBDev *dev);
|
||||
|
||||
// Attach the device
|
||||
void(*handle_attach)(USBDev *dev);
|
||||
|
||||
// Reset the device
|
||||
void(*handle_reset)(USBDev *dev);
|
||||
|
||||
// Process control request.
|
||||
// Called from handle_packet().
|
||||
// Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
// then the number of bytes transferred is stored in p->actual_length
|
||||
void(*handle_control)(USBDev *dev, USBPacket *p, int request, int value,
|
||||
int index, int length, uint8_t *data);
|
||||
|
||||
// Process data transfers (both BULK and ISOC).
|
||||
// Called from handle_packet().
|
||||
// Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
|
||||
// then the number of bytes transferred is stored in p->actual_length
|
||||
void(*handle_data)(USBDev *dev, USBPacket *p);
|
||||
|
||||
void(*set_interface)(USBDev *dev, int Interface,
|
||||
int alt_old, int alt_new);
|
||||
|
||||
// Called when the hcd is done queuing packets for an endpoint, only
|
||||
// necessary for devices which can return USB_RET_ADD_TO_QUEUE.
|
||||
void(*flush_ep_queue)(USBDev *dev, USBEndpoint *ep);
|
||||
|
||||
// Called by the hcd to let the device know the queue for an endpoint
|
||||
// has been unlinked / stopped. Optional may be NULL.
|
||||
void(*EP_Stopped)(USBDev* Dev, USBEndpoint* EP);
|
||||
|
||||
const char *product_desc;
|
||||
const USBDesc *usb_desc;
|
||||
}
|
||||
USBDeviceClass;
|
||||
|
||||
typedef struct _USBCombinedPacket {
|
||||
_USBPacket* First;
|
||||
QTAILQ_HEAD(packets_head, _USBPacket) Packets;
|
||||
IOVector IoVec;
|
||||
}
|
||||
USBCombinedPacket;
|
||||
|
||||
/* Structure used to hold information about an active USB packet */
|
||||
struct _USBPacket {
|
||||
int Pid; // Packet ID (used to identify the type of packet that is being sent)
|
||||
uint32_t Id; // Paddr of the TD for this packet
|
||||
USBEndpoint* Endpoint; // endpoint this packet is transferred to
|
||||
unsigned int Stream;
|
||||
IOVector IoVec; // used to perform vectored I/O
|
||||
uint64_t Parameter; // control transfers
|
||||
bool ShortNotOK; // the bufferRounding mode of the TD for this packet
|
||||
bool IntReq; // whether or not to generate an interrupt for this packet (DelayInterrupt of the TD is zero)
|
||||
int Status; // USB_RET_* status code
|
||||
int ActualLength; // before copy: offset inside IoVec structs; after copy: number of bytes actually transferred
|
||||
// Internal use by the USB layer
|
||||
USBPacketState State;
|
||||
USBCombinedPacket* Combined;
|
||||
QTAILQ_ENTRY(_USBPacket) Queue;
|
||||
QTAILQ_ENTRY(_USBPacket) CombinedEntry;
|
||||
};
|
||||
|
||||
/* Struct describing the status of a usb port */
|
||||
typedef struct _USBPort {
|
||||
XboxDevice* Dev; // usb device (if present)
|
||||
int SpeedMask; // usb speeds supported
|
||||
int HubCount; // number of hubs attached
|
||||
char Path[16]; // the number of the port
|
||||
int PortIndex; // internal port index
|
||||
QTAILQ_ENTRY(_USBPort) Next;
|
||||
}
|
||||
USBPort;
|
||||
|
||||
// Forward declare OHCI class for USBDevice class
|
||||
// Forward declare OHCI class for m_HostController pointer
|
||||
class OHCI;
|
||||
|
||||
/* Helper class which provides various functionality to both OHCI and usb device classes */
|
||||
class USBPCIDevice : public PCIDevice {
|
||||
public:
|
||||
// constructor
|
||||
USBPCIDevice(uint16_t vendorID, uint16_t deviceID, uint8_t revisionID, uint8_t m_irqn);
|
||||
USBPCIDevice(uint16_t vendorID, uint16_t deviceID, uint8_t revisionID, uint8_t m_irqn, Cpu *cpu);
|
||||
virtual ~USBPCIDevice();
|
||||
|
||||
// PCI Device functions
|
||||
|
@ -241,32 +78,32 @@ public:
|
|||
|
||||
// USBDevice-specific functions/variables
|
||||
// pointer to the host controller this device refers to
|
||||
OHCI* m_HostController = nullptr;
|
||||
OHCI* m_HostController;
|
||||
// PCI path of this usb device
|
||||
const char* m_PciPath;
|
||||
|
||||
// register a port with the HC
|
||||
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask);
|
||||
//
|
||||
void USB_DeviceEPstopped(XboxDevice* Dev, USBEndpoint* Ep);
|
||||
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask, USBPortOps* Ops);
|
||||
// reset a usb port
|
||||
void USB_PortReset(USBPort* Port);
|
||||
// a device is attched
|
||||
// update device status during an attach
|
||||
void USB_DeviceAttach(XboxDeviceState* dev);
|
||||
// update port status when a device is attached
|
||||
void USB_Attach(USBPort* Port);
|
||||
// a device is detached
|
||||
// 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, XboxDevice* Child);
|
||||
void ChildDetach(USBPort* Port, XboxDeviceState* Child);
|
||||
// TODO
|
||||
void Wakeup(USBPort* Port);
|
||||
// TODO
|
||||
void Complete(USBPort* Port, USBPacket *P);
|
||||
// reset a device
|
||||
void USB_DeviceReset(XboxDevice* Dev);
|
||||
// find the usb device with the supplied address
|
||||
XboxDevice* USB_FindDevice(USBPort* Port, uint8_t Addr);
|
||||
// ergo720: can probably be removed by calling directly usb_hub_find_device
|
||||
XboxDevice* USB_DeviceFindDevice(XboxDevice* Dev, uint8_t Addr);
|
||||
void USB_DeviceReset(XboxDeviceState* Dev);
|
||||
//
|
||||
XboxDeviceState* USB_DeviceFindDevice(XboxDeviceState* Dev, uint8_t Addr);
|
||||
// find the requested endpoint in the supplied device
|
||||
USBEndpoint* USB_GetEP(XboxDevice* Dev, int Pid, int Ep);
|
||||
USBEndpoint* USB_GetEP(XboxDeviceState* Dev, int Pid, int Ep);
|
||||
// setup a packet for transfer
|
||||
void USB_PacketSetup(USBPacket* p, int Pid, USBEndpoint* Ep, unsigned int Stream,
|
||||
uint64_t Id, bool ShortNotOK, bool IntReq);
|
||||
|
@ -275,36 +112,59 @@ public:
|
|||
// append the user buffer to the packet
|
||||
void USB_PacketAddBuffer(USBPacket* p, void* ptr, size_t len);
|
||||
// transfer and process the packet
|
||||
void USB_HandlePacket(XboxDevice* dev, USBPacket* p);
|
||||
void USB_HandlePacket(XboxDeviceState* dev, USBPacket* p);
|
||||
// check if the packet has the expected state and assert if not
|
||||
void USB_PacketCheckState(USBPacket* p, USBPacketState expected);
|
||||
// process the packet
|
||||
void USB_ProcessOne(USBPacket* p);
|
||||
//
|
||||
void USB_DoParameter(XboxDevice* s, USBPacket* p);
|
||||
void USB_DoParameter(XboxDeviceState* s, USBPacket* p);
|
||||
// process a setup token
|
||||
void USB_DoTokenSetup(XboxDevice* s, USBPacket* p);
|
||||
void USB_DoTokenSetup(XboxDeviceState* s, USBPacket* p);
|
||||
// process an input token
|
||||
void DoTokenIn(XboxDevice* s, USBPacket* p);
|
||||
void DoTokenIn(XboxDeviceState* s, USBPacket* p);
|
||||
// process an output token
|
||||
void DoTokenOut(XboxDevice* s, USBPacket* p);
|
||||
void DoTokenOut(XboxDeviceState* s, USBPacket* p);
|
||||
// copy the packet data to the buffer pointed to by ptr
|
||||
void USB_PacketCopy(USBPacket* p, void* ptr, size_t bytes);
|
||||
// queue a packet to an endpoint
|
||||
void USB_QueueOne(USBPacket* p);
|
||||
//
|
||||
void USB_DeviceHandleControl(XboxDevice* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data);
|
||||
//
|
||||
void USB_DeviceHandleData(XboxDevice* dev, USBPacket* p);
|
||||
//
|
||||
void USB_DeviceFlushEPqueue(XboxDevice* dev, USBEndpoint* ep);
|
||||
//
|
||||
void USB_DeviceCancelPacket(XboxDevice* dev, USBPacket* p);
|
||||
// Cancel an active packet. The packed must have been deferred by
|
||||
// returning USB_RET_ASYNC from handle_packet, and not yet completed
|
||||
void USB_CancelPacket(USBPacket* p);
|
||||
// queue a packet to an endpoint
|
||||
void USB_QueueOne(USBPacket* p);
|
||||
// call usb class init function
|
||||
int USB_DeviceInit(XboxDeviceState* dev);
|
||||
// call usb class find_device function
|
||||
XboxDeviceState * USB_FindDevice(USBPort* Port, uint8_t Addr);
|
||||
// call usb class cancel_packet function
|
||||
void USB_DeviceCancelPacket(XboxDeviceState* dev, USBPacket* p);
|
||||
// call usb class handle_destroy function
|
||||
void USB_DeviceHandleDestroy(XboxDeviceState* dev);
|
||||
// call usb class handle_attach function
|
||||
void USB_DeviceHandleAttach(XboxDeviceState* dev);
|
||||
// call usb class handle_reset function
|
||||
void USB_DeviceHandleReset(XboxDeviceState* dev);
|
||||
// call usb class handle_control function
|
||||
void USB_DeviceHandleControl(XboxDeviceState* dev, USBPacket* p, int request, int value, int index, int length, uint8_t* data);
|
||||
// call usb class handle_data function
|
||||
void USB_DeviceHandleData(XboxDeviceState* dev, USBPacket* p);
|
||||
// call usb class set_interface function
|
||||
void USB_DeviceSetInterface(XboxDeviceState* dev, int iface, int alt_old, int alt_new);
|
||||
// call usb class flush_ep_queue function
|
||||
void USB_DeviceFlushEPqueue(XboxDeviceState* dev, USBEndpoint* ep);
|
||||
// call usb class ep_stopped function
|
||||
void USB_DeviceEPstopped(XboxDeviceState* Dev, USBEndpoint* Ep);
|
||||
// set the type of the endpoint
|
||||
void USB_EPsetType(XboxDeviceState* dev, int pid, int ep, uint8_t type);
|
||||
// set the interface number of the endpoint
|
||||
uint8_t USB_EPsetIfnum(XboxDeviceState* dev, int pid, int ep, uint8_t ifnum);
|
||||
// set the maximum packet size parameter of the endpoint
|
||||
void USB_EPsetMaxPacketSize(XboxDeviceState* dev, int pid, int ep, uint16_t raw);
|
||||
// assign port numbers (also for hubs)
|
||||
void USB_PortLocation(USBPort* downstream, USBPort* upstream, int portnr);
|
||||
private:
|
||||
uint8_t m_irqn;
|
||||
Cpu* m_cpu;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -315,8 +315,8 @@ int Xbox::Initialize(OpenXBOXSettings *settings)
|
|||
m_HostBridge = new HostBridgeDevice(PCI_VENDOR_ID_NVIDIA, 0x02A5, 0xA1);
|
||||
m_MCPXRAM = new MCPXRAMDevice(PCI_VENDOR_ID_NVIDIA, 0x02A6, 0xA1, mcpxRevision);
|
||||
m_LPC = new LPCDevice(PCI_VENDOR_ID_NVIDIA, 0x01B2, 0xD4, m_IRQs);
|
||||
m_USB1 = new USBPCIDevice(PCI_VENDOR_ID_NVIDIA, 0x02A5, 0xA1, 1);
|
||||
m_USB2 = new USBPCIDevice(PCI_VENDOR_ID_NVIDIA, 0x02A5, 0xA1, 9);
|
||||
m_USB1 = new USBPCIDevice(PCI_VENDOR_ID_NVIDIA, 0x02A5, 0xA1, 1, m_cpu);
|
||||
m_USB2 = new USBPCIDevice(PCI_VENDOR_ID_NVIDIA, 0x02A5, 0xA1, 9, m_cpu);
|
||||
m_NVNet = new NVNetDevice(PCI_VENDOR_ID_NVIDIA, 0x01C3, 0xD2);
|
||||
m_NVAPU = new NVAPUDevice(PCI_VENDOR_ID_NVIDIA, 0x01B0, 0xD2);
|
||||
m_AC97 = new AC97Device(PCI_VENDOR_ID_NVIDIA, 0x01B1, 0xD2);
|
||||
|
|
Loading…
Reference in a new issue