Added skeleton HC initialization

This commit is contained in:
ergo720 2018-05-03 20:13:42 +02:00
parent 403f9cb710
commit b61339f0ea
3 changed files with 120 additions and 10 deletions

View File

@ -35,7 +35,60 @@
// ******************************************************************
#include "OHCI.h"
#include "..\CxbxKrnl\CxbxKrnl.h"
// global pointers to the two USB host controllers available on the Xbox
OHCI_State* g_pHostController1 = nullptr;
OHCI_State* g_pHostController2 = nullptr;
void OHCI_State::HC_Reset(USB_State new_state)
{
// 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
// Reset all registers
if (new_state == USB_Reset) {
// Remark: the standard says that RemoteWakeupConnected bit should be set during POST, cleared during hw reset
// and ignored during a sw reset. However, VBox sets it on hw reset and XQEMU clears it. Considering that the Xbox
// doesn't do POST, I will clear it.
HC_Registers.HcControl = 0;
}
else {
HC_Registers.HcControl &= (OHCI_CTL_IR | OHCI_CTL_RWC);
}
HC_Registers.HcControl = ~OHCI_CTL_HCFS;
HC_Registers.HcControl = new_state;
HC_Registers.HcCommandStatus = 0;
HC_Registers.HcInterruptStatus = 0;
HC_Registers.HcInterruptEnable = OHCI_INTR_MASTER_INTERRUPT_ENABLED; // enable interrupts
HC_Registers.HcHCCA = 0;
HC_Registers.HcPeriodCurrentED = 0;
HC_Registers.HcControlHeadED = HC_Registers.HcControlCurrentED = 0;
HC_Registers.HcBulkHeadED = HC_Registers.HcBulkCurrentED = 0;
HC_Registers.HcDoneHead = 0;
HC_Registers.HcFmInterval = 0;
HC_Registers.HcFmInterval |= (0x2778 << 16); // TBD according to the standard, using what XQEMU sets (FSLargestDataPacket)
HC_Registers.HcFmInterval |= (0 << 31); // redundant, but we'll do it for the sake of completeness (FrameIntervalToggle)
HC_Registers.HcFmInterval |= 0x2EDF; // bit-time of a frame. 1 frame = 1 ms (FrameInterval)
HC_Registers.HcFmRemaining = 0;
HC_Registers.HcFmNumber = 0;
HC_Registers.HcPeriodicStart = 0;
HC_Registers.HcRhDescriptorA = OHCI_RHA_NPS | 2; // The xbox lacks the hw to switch off the power on the ports and has 2 ports per HC
HC_Registers.HcRhDescriptorB = 0; // The attached devices are removable and use PowerSwitchingMode to control the power on the ports
for (int i = 0; i < 2; i++)
{
OHCIPort* Port = &HC_Registers.RhPort[i];
Port->HcRhPortStatus = 0;
//if (Port->port.device && Port->port.device->attached) {
//usb_port_reset(&Port->port);
//}
}
DbgPrintf("usb-ohci: Reset\n");
}

View File

@ -40,6 +40,47 @@
#include <stdint.h>
#include "Cxbx.h"
// Abbreviations used:
// OHCI: Open Host Controller Interface; the standard used on the xbox to comunicate with the usb devices
// HC: Host Controller; the hardware which interfaces with the usb device and the usb driver
// HCD: Host Controller Driver; software which talks to the HC, it's linked in the xbe
// These macros are used to access the bits in the various registers
// HcControl
#define OHCI_CTL_CBSR ((1<<0)|(1<<1)) // ControlBulkServiceRatio
#define OHCI_CTL_PLE (1<<2) // PeriodicListEnable
#define OHCI_CTL_IE (1<<3) // IsochronousEnable
#define OHCI_CTL_CLE (1<<4) // ControlListEnable
#define OHCI_CTL_BLE (1<<5) // BulkListEnable
#define OHCI_CTL_HCFS ((1<<6)|(1<<7)) // HostControllerFunctionalState
#define OHCI_CTL_IR (1<<8) // InterruptRouting
#define OHCI_CTL_RWC (1<<9) // RemoteWakeupConnected
#define OHCI_CTL_RWE (1<<10) // RemoteWakeupEnable
// HcInterruptEnable, HcInterruptDisable
#define OHCI_INTR_MASTER_INTERRUPT_ENABLED (1<<31) // MasterInterruptEnable
// HcRhDescriptorA
#define OHCI_RHA_PSM (1<<8) // PowerSwitchingMode
#define OHCI_RHA_NPS (1<<9) // NoPowerSwitching
#define OHCI_RHA_DT (1<<10) // DeviceType
#define OHCI_RHA_OCPM (1<<11) // OverCurrentProtectionMode
#define OHCI_RHA_NOCP (1<<12) // NoOverCurrentProtection
// Struct describing the status of a usb port
struct USBPort {
//USBDevice* device;
//TODO
};
// Small struct used to hold the HcRhPortStatus register and the usb port status
typedef struct _OHCIPort
{
USBPort port;
uint32_t HcRhPortStatus;
}
OHCIPort;
// All these registers are well documented in the OHCI standard
typedef struct _OHCI_Registers
{
@ -71,11 +112,20 @@ typedef struct _OHCI_Registers
uint32_t HcRhDescriptorA;
uint32_t HcRhDescriptorB;
uint32_t HcRhStatus;
uint32_t HcRhPortStatus1; // 2 ports per HC, for a total of 4 USB ports
uint32_t HcRhPortStatus2;
OHCIPort RhPort[2]; // 2 ports per HC, for a total of 4 USB ports
}
OHCI_Registers;
// enum indicating the current HC state
typedef enum _USB_State
{
USB_Reset = 0x00,
USB_Resume = 0x40,
USB_Operational = 0x80,
USB_Suspend = 0xC0,
}
USB_State;
/* OHCI class representing the state of the HC */
class OHCI_State
@ -86,13 +136,15 @@ class OHCI_State
// destructor
~OHCI_State() {}
// read a register
uint32_t ReadRegister(xbaddr addr);
uint32_t HC_ReadRegister(xbaddr addr);
// write a register
void WriteRegister(xbaddr addr, uint32_t value);
void HC_WriteRegister(xbaddr addr, uint32_t value);
// reset the HC to the default state
void HC_Reset(USB_State new_state);
private:
// all the registers available on the OHCI standard
OHCI_Registers Registers;
OHCI_Registers HC_Registers;
};
extern OHCI_State* g_pHostController1;

View File

@ -51,7 +51,12 @@ void USBDevice::Init(unsigned int address)
m_DeviceId = 0x01C2;
m_VendorId = PCI_VENDOR_ID_NVIDIA;
// TODO: construct the OHCI object
g_pHostController1 = new OHCI_State;
g_pHostController2 = new OHCI_State;
// We can use the USB_Reset state to also cold boot the HC during initialization
g_pHostController1->HC_Reset(USB_Reset);
g_pHostController2->HC_Reset(USB_Reset);
}
uint32_t USBDevice::MMIORead(int barIndex, uint32_t addr, unsigned size)
@ -62,11 +67,11 @@ uint32_t USBDevice::MMIORead(int barIndex, uint32_t addr, unsigned size)
// Figure out the correct OHCI object and read the register
if (addr >= USB1_BASE) {
// USB1 queried
return g_pHostController2->ReadRegister(addr);
return g_pHostController2->HC_ReadRegister(addr);
}
// USB0 queried
return g_pHostController1->ReadRegister(addr);
return g_pHostController1->HC_ReadRegister(addr);
}
void USBDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned size)
@ -77,10 +82,10 @@ void USBDevice::MMIOWrite(int barIndex, uint32_t addr, uint32_t value, unsigned
// Figure out the correct OHCI object and write the value to the register
if (addr >= USB1_BASE) {
// USB1 queried
g_pHostController2->WriteRegister(addr, value);
g_pHostController2->HC_WriteRegister(addr, value);
return;
}
// USB0 queried
g_pHostController1->WriteRegister(addr, value);
g_pHostController1->HC_WriteRegister(addr, value);
}