Usb port stuff (wip)
This commit is contained in:
parent
685227d874
commit
421a5b8754
|
@ -47,18 +47,13 @@ typedef enum _USB_SPEED
|
|||
}
|
||||
USB_SPEED;
|
||||
|
||||
// global pointers to the two USB host controllers available on the Xbox
|
||||
OHCI* g_pHostController1 = nullptr;
|
||||
OHCI* g_pHostController2 = nullptr;
|
||||
|
||||
|
||||
OHCI::OHCI(USBDevice* UsbObj, int Irq)
|
||||
OHCI::OHCI(int Irq)
|
||||
{
|
||||
UsbInstance = UsbObj;
|
||||
Irq_n = Irq;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
UsbInstance->USB_RegisterPort(&Registers.RhPort[i].Port, this, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
USB_RegisterPort(&Registers.RhPort[i].UsbPort, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
|
||||
}
|
||||
OHCI_PacketInit(&UsbPacket);
|
||||
|
||||
|
@ -79,7 +74,7 @@ void OHCI::OHCI_StateReset()
|
|||
// The usb state can be USB_Suspend if it is a software reset, and USB_Reset if it is a hardware
|
||||
// reset or cold boot
|
||||
|
||||
// TODO: stop all the list processing here
|
||||
OHCI_BusStop();
|
||||
|
||||
// Reset all registers
|
||||
// Remark: the standard says that RemoteWakeupConnected bit should be set during POST, cleared during hw reset
|
||||
|
@ -112,10 +107,12 @@ void OHCI::OHCI_StateReset()
|
|||
{
|
||||
OHCIPort* Port = &Registers.RhPort[i];
|
||||
Port->HcRhPortStatus = 0;
|
||||
//if (Port->port.device && Port->port.device->attached) {
|
||||
//usb_port_reset(&Port->port);
|
||||
//}
|
||||
if (Port->UsbPort.Dev && Port->UsbPort.Dev->Attached) {
|
||||
USB_PortReset(&Port->UsbPort);
|
||||
}
|
||||
}
|
||||
|
||||
OHCI_StopEndpoints();
|
||||
|
||||
DbgPrintf("Ohci: Reset event.\n");
|
||||
}
|
||||
|
@ -443,3 +440,82 @@ void OHCI::OHCI_SetInterrupt(uint32_t Value)
|
|||
Registers.HcInterruptStatus |= Value;
|
||||
OHCI_UpdateInterrupt();
|
||||
}
|
||||
|
||||
void OHCI::OHCI_StopEndpoints()
|
||||
{
|
||||
USBDev* dev;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
dev = Registers.RhPort[i].UsbPort.Dev;
|
||||
if (dev && dev->Attached) {
|
||||
USB_DeviceEPstopped(dev, &dev->EP_ctl);
|
||||
for (j = 0; j < USB_MAX_ENDPOINTS; j++) {
|
||||
USB_DeviceEPstopped(dev, &dev->EP_in[j]);
|
||||
USB_DeviceEPstopped(dev, &dev->EP_out[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OHCI::OHCI_Detach(USBPort* Port)
|
||||
{
|
||||
OHCIPort* port = &Registers.RhPort[Port->PortIndex];
|
||||
uint32_t old_state = port->HcRhPortStatus;
|
||||
|
||||
ohci_async_cancel_device(Port->Dev);
|
||||
|
||||
// set connect status
|
||||
if (port->HcRhPortStatus & OHCI_PORT_CCS) {
|
||||
port->HcRhPortStatus &= ~OHCI_PORT_CCS;
|
||||
port->HcRhPortStatus |= OHCI_PORT_CSC;
|
||||
}
|
||||
// disable port
|
||||
if (port->HcRhPortStatus & OHCI_PORT_PES) {
|
||||
port->HcRhPortStatus &= ~OHCI_PORT_PES;
|
||||
port->HcRhPortStatus |= OHCI_PORT_PESC;
|
||||
}
|
||||
|
||||
DbgPrintf("Ohci: Detached port %d\n", Port->PortIndex);
|
||||
|
||||
if (old_state != port->HcRhPortStatus) {
|
||||
OHCI_SetInterrupt(OHCI_INTR_RHSC);
|
||||
}
|
||||
}
|
||||
|
||||
void OHCI::USB_RegisterPort(USBPort* Port, int Index, int SpeedMask)
|
||||
{
|
||||
Port->PortIndex = Index;
|
||||
Port->SpeedMask = SpeedMask;
|
||||
Port->HubCount = 0;
|
||||
std::snprintf(Port->Path, sizeof(Port->Path), "%d", Index + 1);
|
||||
}
|
||||
|
||||
void OHCI::USB_DeviceEPstopped(USBDev* 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);
|
||||
}
|
||||
}
|
||||
|
||||
void OHCI::USB_PortReset(USBPort* Port)
|
||||
{
|
||||
USBDev* dev = Port->Dev;
|
||||
|
||||
assert(dev != nullptr);
|
||||
USB_Detach(Port);
|
||||
usb_attach(port);
|
||||
usb_device_reset(dev);
|
||||
}
|
||||
|
||||
void OHCI::USB_Detach(USBPort* Port)
|
||||
{
|
||||
USBDev* dev = Port->Dev;
|
||||
|
||||
assert(dev != nullptr);
|
||||
assert(dev->State != USB_STATE_NOTATTACHED);
|
||||
OHCI_Detach(Port);
|
||||
dev->State = USB_STATE_NOTATTACHED;
|
||||
}
|
|
@ -66,7 +66,15 @@
|
|||
#define OHCI_STATUS_OCR (1<<3) // OwnershipChangeRequest
|
||||
#define OHCI_STATUS_SOC ((1<<6)|(1<<7)) // SchedulingOverrunCount
|
||||
// HcInterruptStatus
|
||||
#define OHCI_INTR_SO (1<<0) // Scheduling overrun
|
||||
#define OHCI_INTR_WD (1<<1) // HcDoneHead writeback
|
||||
#define OHCI_INTR_SF (1<<2) // Start of frame
|
||||
#define OHCI_INTR_RD (1<<3) // Resume detect
|
||||
#define OHCI_INTR_UE (1<<4) // Unrecoverable error
|
||||
#define OHCI_INTR_FNO (1<<5) // Frame number overflow
|
||||
#define OHCI_INTR_RHSC (1<<6) // Root hub status change
|
||||
#define OHCI_INTR_OC (1<<30) // Ownership change
|
||||
#define OHCI_INTR_MIE (1<<31) // Master Interrupt Enable
|
||||
// HcInterruptEnable, HcInterruptDisable
|
||||
#define OHCI_INTR_MIE (1<<31) // MasterInterruptEnable
|
||||
// HcHCCA
|
||||
|
@ -84,8 +92,20 @@
|
|||
#define OHCI_RHA_OCPM (1<<11) // OverCurrentProtectionMode
|
||||
#define OHCI_RHA_NOCP (1<<12) // NoOverCurrentProtection
|
||||
// HcRhPortStatus
|
||||
#define OHCI_PORT_CCS (1<<0) // CurrentConnectStatus
|
||||
#define OHCI_PORT_PES (1<<1) // PortEnableStatus
|
||||
#define OHCI_PORT_PSS (1<<2) // PortSuspendStatus
|
||||
#define OHCI_PORT_POCI (1<<3) // PortOverCurrentIndicator
|
||||
#define OHCI_PORT_PRS (1<<4) // PortResetStatus
|
||||
#define OHCI_PORT_PPS (1<<8) // PortPowerStatus
|
||||
|
||||
#define OHCI_PORT_LSDA (1<<9) // LowSpeedDeviceAttached
|
||||
#define OHCI_PORT_CSC (1<<16) // ConnectStatusChange
|
||||
#define OHCI_PORT_PESC (1<<17) // PortEnableStatusChange
|
||||
#define OHCI_PORT_PSSC (1<<18) // PortSuspendStatusChange
|
||||
#define OHCI_PORT_OCIC (1<<19) // PortOverCurrentIndicatorChange
|
||||
#define OHCI_PORT_PRSC (1<<20) // PortResetStatusChange
|
||||
#define OHCI_PORT_WTC (OHCI_PORT_CSC|OHCI_PORT_PESC|OHCI_PORT_PSSC \
|
||||
|OHCI_PORT_OCIC|OHCI_PORT_PRSC)
|
||||
|
||||
// enum indicating the current HC state
|
||||
typedef enum _OHCI_State
|
||||
|
@ -100,7 +120,7 @@ OHCI_State;
|
|||
// Small struct used to hold the HcRhPortStatus register and the usb port status
|
||||
typedef struct _OHCIPort
|
||||
{
|
||||
USBPort Port;
|
||||
USBPort UsbPort;
|
||||
uint32_t HcRhPortStatus;
|
||||
}
|
||||
OHCIPort;
|
||||
|
@ -135,6 +155,8 @@ typedef struct _OHCI_Registers
|
|||
uint32_t HcRhDescriptorA;
|
||||
uint32_t HcRhDescriptorB;
|
||||
uint32_t HcRhStatus;
|
||||
// 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;
|
||||
|
@ -145,7 +167,7 @@ class OHCI
|
|||
{
|
||||
public:
|
||||
// constructor
|
||||
OHCI(USBDevice* UsbObj, int Irqn);
|
||||
OHCI(int Irqn);
|
||||
// destructor
|
||||
~OHCI() {}
|
||||
// read a register
|
||||
|
@ -165,8 +187,6 @@ class OHCI
|
|||
uint64_t UsbFrameTime;
|
||||
// ticks per usb tick
|
||||
uint64_t TicksPerUsbTick;
|
||||
// the usb device instance of this HC
|
||||
USBDevice* UsbInstance;
|
||||
// usb packet
|
||||
USBPacket UsbPacket;
|
||||
// irq number
|
||||
|
@ -192,9 +212,27 @@ class OHCI
|
|||
void OHCI_UpdateInterrupt();
|
||||
// fire an interrupt
|
||||
void OHCI_SetInterrupt(uint32_t Value);
|
||||
//
|
||||
void OHCI_StopEndpoints();
|
||||
// update ohci registers during a device detach
|
||||
void OHCI_Detach(USBPort* Port);
|
||||
|
||||
// register a port with the HC
|
||||
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask);
|
||||
//
|
||||
void USB_DeviceEPstopped(USBDev* Dev, USBEndpoint* EP);
|
||||
// reset a usb port
|
||||
void USB_PortReset(USBPort* Port);
|
||||
// a device is attched
|
||||
void Attach(USBPort* port);
|
||||
// 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, USBDev* child);
|
||||
// TODO
|
||||
void Wakeup(USBPort* port);
|
||||
// TODO
|
||||
void Complete(USBPort* port, USBPacket *p);
|
||||
};
|
||||
|
||||
extern OHCI* g_pHostController1;
|
||||
extern OHCI* g_pHostController2;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
|
||||
#include "USBDevice.h"
|
||||
#include "OHCI.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
void USBDevice::Init(unsigned int address)
|
||||
|
@ -53,11 +52,11 @@ void USBDevice::Init(unsigned int address)
|
|||
m_VendorId = PCI_VENDOR_ID_NVIDIA;
|
||||
|
||||
if (address == USB0_BASE) {
|
||||
g_pHostController1 = new OHCI(this, 1);
|
||||
m_pHostController1 = new OHCI(1);
|
||||
return;
|
||||
}
|
||||
|
||||
g_pHostController2 = new OHCI(this, 9);
|
||||
m_pHostController2 = new OHCI(9);
|
||||
}
|
||||
|
||||
uint32_t USBDevice::MMIORead(int barIndex, uint32_t addr, unsigned size)
|
||||
|
@ -66,13 +65,13 @@ uint32_t USBDevice::MMIORead(int barIndex, uint32_t addr, unsigned size)
|
|||
assert(barIndex == 0);
|
||||
|
||||
// Figure out the correct OHCI object and read the register
|
||||
if (addr >= USB1_BASE) {
|
||||
// USB1 queried
|
||||
return g_pHostController2->OHCI_ReadRegister(addr);
|
||||
if (addr >= USB0_BASE) {
|
||||
// USB0 queried
|
||||
return m_pHostController1->OHCI_ReadRegister(addr);
|
||||
}
|
||||
|
||||
// USB0 queried
|
||||
return g_pHostController1->OHCI_ReadRegister(addr);
|
||||
// USB1 queried
|
||||
return m_pHostController2->OHCI_ReadRegister(addr);
|
||||
}
|
||||
|
||||
void USBDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size)
|
||||
|
@ -81,21 +80,12 @@ void USBDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned
|
|||
assert(barIndex == 0);
|
||||
|
||||
// Figure out the correct OHCI object and write the value to the register
|
||||
if (addr >= USB1_BASE) {
|
||||
// USB1 queried
|
||||
g_pHostController2->OHCI_WriteRegister(addr, value);
|
||||
if (addr >= USB0_BASE) {
|
||||
// USB0 queried
|
||||
m_pHostController1->OHCI_WriteRegister(addr, value);
|
||||
return;
|
||||
}
|
||||
|
||||
// USB0 queried
|
||||
g_pHostController1->OHCI_WriteRegister(addr, value);
|
||||
}
|
||||
|
||||
void USBDevice::USB_RegisterPort(USBPort* Port, OHCI* Obj, int Index, int SpeedMask)
|
||||
{
|
||||
Port->Opaque = Obj;
|
||||
Port->PortIndex = Index;
|
||||
Port->SpeedMask = SpeedMask;
|
||||
Port->HubCount = 0;
|
||||
std::snprintf(Port->Path, sizeof(Port->Path), "%d", Index + 1);
|
||||
// USB1 queried
|
||||
m_pHostController2->OHCI_WriteRegister(addr, value);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,23 @@
|
|||
#define USBDEVICE_H_
|
||||
|
||||
#include "..\PCIDevice.h"
|
||||
#include <assert.h>
|
||||
|
||||
#define USB_MAX_ENDPOINTS 15
|
||||
#define USB_MAX_INTERFACES 16
|
||||
|
||||
#define USB_STATE_NOTATTACHED 0
|
||||
#define USB_STATE_ATTACHED 1
|
||||
|
||||
typedef enum USBPacketState {
|
||||
USB_PACKET_UNDEFINED = 0,
|
||||
USB_PACKET_SETUP,
|
||||
USB_PACKET_QUEUED,
|
||||
USB_PACKET_ASYNC,
|
||||
USB_PACKET_COMPLETE,
|
||||
USB_PACKET_CANCELED,
|
||||
}
|
||||
USBPacketState;
|
||||
|
||||
// This is a linux struct for vectored I/O. See readv() and writev()
|
||||
typedef struct _IoVec
|
||||
|
@ -56,6 +72,20 @@ typedef struct _IOVector
|
|||
}
|
||||
IOVector;
|
||||
|
||||
typedef struct _USBEndpoint
|
||||
{
|
||||
uint8_t nr;
|
||||
uint8_t pid;
|
||||
uint8_t type;
|
||||
uint8_t ifnum;
|
||||
int max_packet_size;
|
||||
bool pipeline;
|
||||
bool halted;
|
||||
USBDev *dev;
|
||||
//QTAILQ_HEAD(, USBPacket) queue;
|
||||
}
|
||||
USBEndpoint;
|
||||
|
||||
// definition of a USB device
|
||||
typedef struct _USBDev
|
||||
{
|
||||
|
@ -73,9 +103,9 @@ typedef struct _USBDev
|
|||
uint8_t addr;
|
||||
char product_desc[32];
|
||||
int auto_attach;
|
||||
int attached;
|
||||
int Attached; // device is attached
|
||||
|
||||
int32_t state;
|
||||
int32_t State; // current state of device
|
||||
uint8_t setup_buf[8];
|
||||
uint8_t data_buf[4096];
|
||||
int32_t remote_wakeup;
|
||||
|
@ -83,9 +113,9 @@ typedef struct _USBDev
|
|||
int32_t setup_len;
|
||||
int32_t setup_index;
|
||||
|
||||
USBEndpoint ep_ctl;
|
||||
USBEndpoint ep_in[USB_MAX_ENDPOINTS];
|
||||
USBEndpoint ep_out[USB_MAX_ENDPOINTS];
|
||||
USBEndpoint EP_ctl;
|
||||
USBEndpoint EP_in[USB_MAX_ENDPOINTS];
|
||||
USBEndpoint EP_out[USB_MAX_ENDPOINTS];
|
||||
|
||||
//QLIST_HEAD(, USBDescString) strings;
|
||||
const USBDesc *usb_desc; // Overrides class usb_desc if not NULL
|
||||
|
@ -99,19 +129,56 @@ typedef struct _USBDev
|
|||
}
|
||||
USBDev;
|
||||
|
||||
typedef struct _USBEndpoint
|
||||
typedef struct USBDeviceClass
|
||||
{
|
||||
uint8_t nr;
|
||||
uint8_t pid;
|
||||
uint8_t type;
|
||||
uint8_t ifnum;
|
||||
int max_packet_size;
|
||||
bool pipeline;
|
||||
bool halted;
|
||||
USBDevice *dev;
|
||||
//QTAILQ_HEAD(, USBPacket) queue;
|
||||
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;
|
||||
}
|
||||
USBEndpoint;
|
||||
USBDeviceClass;
|
||||
|
||||
// Structure used to hold information about an active USB packet
|
||||
typedef struct _USBPacket
|
||||
|
@ -137,23 +204,12 @@ USBPacket;
|
|||
|
||||
// Struct describing the status of a usb port
|
||||
typedef struct _USBPort {
|
||||
USBDev *Dev;
|
||||
USBDev* Dev; // usb device (if present)
|
||||
int SpeedMask; // usb speeds supported
|
||||
int HubCount; // number of hubs attached
|
||||
char Path[16]; // the number of the port
|
||||
OHCI* Opaque; // OHCI* to let USBPort access it
|
||||
int PortIndex; // internal port index, may be used with the Opaque
|
||||
int PortIndex; // internal port index
|
||||
//QTAILQ_ENTRY(USBPort) next;
|
||||
// a device is attched
|
||||
void Attach(USBPort* port);
|
||||
// a device is detached
|
||||
void Detach(USBPort* port);
|
||||
// a device downstream from the device attached to the port (attached through a hub) is detached
|
||||
void ChildDetach(USBPort* port, USBDev* child);
|
||||
// TODO
|
||||
void Wakeup(USBPort* port);
|
||||
// TODO
|
||||
void Complete(USBPort* port, USBPacket *p);
|
||||
}
|
||||
USBPort;
|
||||
|
||||
|
@ -174,9 +230,10 @@ class USBDevice : public PCIDevice {
|
|||
uint32_t MMIORead(int barIndex, uint32_t addr, unsigned size);
|
||||
void MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size);
|
||||
|
||||
// USB specific functions
|
||||
// register a port with the HC
|
||||
void USB_RegisterPort(USBPort* Port, OHCI* Obj, int Index, int SpeedMask);
|
||||
|
||||
// pointers to the two USB host controllers available on the Xbox
|
||||
OHCI* m_pHostController1 = nullptr;
|
||||
OHCI* m_pHostController2 = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue