More usb port stuff

This commit is contained in:
ergo720 2018-05-29 09:57:53 +02:00
parent 421a5b8754
commit 0fd31a0df6
3 changed files with 221 additions and 18 deletions

View File

@ -39,6 +39,9 @@
#define USB_HZ 12000000
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
typedef enum _USB_SPEED
{
@ -50,7 +53,7 @@ USB_SPEED;
OHCI::OHCI(int Irq)
{
Irq_n = Irq;
IrqNum = Irq;
for (int i = 0; i < 2; i++) {
USB_RegisterPort(&Registers.RhPort[i].UsbPort, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
@ -114,7 +117,7 @@ void OHCI::OHCI_StateReset()
OHCI_StopEndpoints();
DbgPrintf("Ohci: Reset event.\n");
DbgPrintf("Ohci: Reset mode event.\n");
}
void OHCI::OHCI_BusStart()
@ -122,7 +125,7 @@ void OHCI::OHCI_BusStart()
// Create the end-of-frame timer. Let's try a factor of 50 (1 virtual ms -> 50 real ms)
pEOFtimer = Timer_Create(OHCI_FrameBoundaryWrapper, this, 50);
DbgPrintf("Ohci: Operational event\n");
DbgPrintf("Ohci: Operational mode event\n");
// SOF event
OHCI_SOF();
@ -163,11 +166,11 @@ void OHCI::OHCI_ChangeState(uint32_t Value)
case Suspend:
OHCI_BusStop();
DbgPrintf("Ohci: Suspend event\n");
DbgPrintf("Ohci: Suspend mode event\n");
break;
case Resume:
DbgPrintf("Ohci: Resume event\n");
DbgPrintf("Ohci: Resume mode event\n");
break;
case Reset:
@ -175,7 +178,7 @@ void OHCI::OHCI_ChangeState(uint32_t Value)
break;
default:
EmuWarning("Ohci: Unknown USB state mode!");
EmuWarning("Ohci: Unknown USB mode!");
}
}
@ -410,15 +413,15 @@ void OHCI::OHCI_WriteRegister(xbaddr Addr, uint32_t Value)
break;
case 20: // HcRhStatus
// TODO
OHCI_SetHubStatus(Value);
break;
case 21: // RhPort 0
// TODO
OHCI_PortSetStatus(0, Value);
break;
case 22: // RhPort 1
// TODO
OHCI_PortSetStatus(1, Value);
break;
default:
@ -430,9 +433,9 @@ void OHCI::OHCI_WriteRegister(xbaddr Addr, uint32_t Value)
void OHCI::OHCI_UpdateInterrupt()
{
if ((Registers.HcInterrupt & OHCI_INTR_MIE) && (Registers.HcInterruptStatus & Registers.HcInterrupt)) {
HalSystemInterrupts[Irq_n].Assert(true);
HalSystemInterrupts[IrqNum].Assert(true);
}
else { HalSystemInterrupts[Irq_n].Assert(false); }
else { HalSystemInterrupts[IrqNum].Assert(false); }
}
void OHCI::OHCI_SetInterrupt(uint32_t Value)
@ -458,6 +461,133 @@ void OHCI::OHCI_StopEndpoints()
}
}
void OHCI::OHCI_SetHubStatus(uint32_t Value)
{
uint32_t old_state;
old_state = Registers.HcRhStatus;
// write 1 to clear OCIC
if (Value & OHCI_RHS_OCIC) {
Registers.HcRhStatus &= ~OHCI_RHS_OCIC;
}
if (Value & OHCI_RHS_LPS) {
int i;
for (i = 0; i < 2; i++) {
OHCI_PortPower(i, 0);
}
DbgPrintf("Ohci: powered down all ports\n");
}
if (Value & OHCI_RHS_LPSC) {
int i;
for (i = 0; i < 2; i++) {
OHCI_PortPower(i, 1);
}
DbgPrintf("Ohci: powered up all ports\n");
}
if (Value & OHCI_RHS_DRWE) {
Registers.HcRhStatus |= OHCI_RHS_DRWE;
}
if (Value & OHCI_RHS_CRWE) {
Registers.HcRhStatus &= ~OHCI_RHS_DRWE;
}
if (old_state != Registers.HcRhStatus) {
OHCI_SetInterrupt(OHCI_INTR_RHSC);
}
}
void OHCI::OHCI_PortPower(int i, int p)
{
if (p) {
Registers.RhPort[i].HcRhPortStatus |= OHCI_PORT_PPS;
}
else {
Registers.RhPort[i].HcRhPortStatus &= ~(OHCI_PORT_PPS |
OHCI_PORT_CCS |
OHCI_PORT_PSS |
OHCI_PORT_PRS);
}
}
void OHCI::OHCI_PortSetStatus(int PortNum, uint32_t Value)
{
uint32_t old_state;
OHCIPort* port;
port = &Registers.RhPort[PortNum];
old_state = port->HcRhPortStatus;
// Write to clear CSC, PESC, PSSC, OCIC, PRSC
if (Value & OHCI_PORT_WTC) {
port->HcRhPortStatus &= ~(Value & OHCI_PORT_WTC);
}
if (Value & OHCI_PORT_CCS) {
port->HcRhPortStatus &= ~OHCI_PORT_PES;
}
OHCI_PortSetIfConnected(PortNum, Value & OHCI_PORT_PES);
if (OHCI_PortSetIfConnected(PortNum, Value & OHCI_PORT_PSS)) {
DbgPrintf("Ohci: port %d: SUSPEND\n", PortNum);
}
if (OHCI_PortSetIfConnected(PortNum, Value & OHCI_PORT_PRS)) {
DbgPrintf("Ohci: port %d: RESET\n", PortNum);
USB_DeviceReset(port->UsbPort.Dev);
port->HcRhPortStatus &= ~OHCI_PORT_PRS;
// ??? Should this also set OHCI_PORT_PESC
port->HcRhPortStatus |= OHCI_PORT_PES | OHCI_PORT_PRSC;
}
// Invert order here to ensure in ambiguous case, device is powered up...
if (Value & OHCI_PORT_LSDA) {
OHCI_PortPower(PortNum, 0);
}
if (Value & OHCI_PORT_PPS) {
OHCI_PortPower(PortNum, 1);
}
if (old_state != port->HcRhPortStatus) {
OHCI_SetInterrupt(OHCI_INTR_RHSC);
}
}
int OHCI::OHCI_PortSetIfConnected(int i, uint32_t Value)
{
int ret = 1;
// writing a 0 has no effect
if (Value == 0) {
return 0;
}
// If CurrentConnectStatus is cleared we set ConnectStatusChange
if (!(Registers.RhPort[i].HcRhPortStatus & OHCI_PORT_CCS)) {
Registers.RhPort[i].HcRhPortStatus |= OHCI_PORT_CSC;
if (Registers.HcRhStatus & OHCI_RHS_DRWE) {
// TODO: CSC is a wakeup event
}
return 0;
}
if (Registers.RhPort[i].HcRhPortStatus & Value)
ret = 0;
// set the bit
Registers.RhPort[i].HcRhPortStatus |= Value;
return ret;
}
void OHCI::OHCI_Detach(USBPort* Port)
{
OHCIPort* port = &Registers.RhPort[Port->PortIndex];
@ -483,6 +613,34 @@ void OHCI::OHCI_Detach(USBPort* Port)
}
}
void OHCI::OHCI_Attach(USBPort* Port)
{
OHCIPort* port = &Registers.RhPort[Port->PortIndex];
uint32_t old_state = port->HcRhPortStatus;
// set connect status
port->HcRhPortStatus |= OHCI_PORT_CCS | OHCI_PORT_CSC;
// update speed
if (port->UsbPort.Dev->speed == USB_SPEED_LOW) {
port->HcRhPortStatus |= OHCI_PORT_LSDA;
}
else {
port->HcRhPortStatus &= ~OHCI_PORT_LSDA;
}
// notify of remote-wakeup
if ((Registers.HcControl & OHCI_CTL_HCFS) == Suspend) {
OHCI_SetInterrupt(OHCI_INTR_RD);
}
DbgPrintf("Ohci: Attached 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;
@ -506,8 +664,8 @@ void OHCI::USB_PortReset(USBPort* Port)
assert(dev != nullptr);
USB_Detach(Port);
usb_attach(port);
usb_device_reset(dev);
USB_Attach(Port);
USB_DeviceReset(dev);
}
void OHCI::USB_Detach(USBPort* Port)
@ -518,4 +676,28 @@ void OHCI::USB_Detach(USBPort* Port)
assert(dev->State != USB_STATE_NOTATTACHED);
OHCI_Detach(Port);
dev->State = USB_STATE_NOTATTACHED;
}
}
void OHCI::USB_Attach(USBPort* Port)
{
USBDev *dev = Port->Dev;
assert(dev != nullptr);
assert(dev->Attached);
assert(dev->State == USB_STATE_NOTATTACHED);
OHCI_Attach(Port);
dev->State = USB_STATE_ATTACHED;
usb_device_handle_attach(dev);
}
void OHCI::USB_DeviceReset(USBDev* dev)
{
if (dev == nullptr || !dev->Attached) {
return;
}
dev->RemoteWakeup = 0;
dev->Addr = 0;
dev->State = USB_STATE_DEFAULT;
usb_device_handle_reset(dev);
}

View File

@ -91,6 +91,13 @@
#define OHCI_RHA_DT (1<<10) // DeviceType
#define OHCI_RHA_OCPM (1<<11) // OverCurrentProtectionMode
#define OHCI_RHA_NOCP (1<<12) // NoOverCurrentProtection
// HcRhStatus
#define OHCI_RHS_LPS (1<<0) // LocalPowerStatus
#define OHCI_RHS_OCI (1<<1) // OverCurrentIndicator
#define OHCI_RHS_DRWE (1<<15) // DeviceRemoteWakeupEnable
#define OHCI_RHS_LPSC (1<<16) // LocalPowerStatusChange
#define OHCI_RHS_OCIC (1<<17) // OverCurrentIndicatorChange
#define OHCI_RHS_CRWE (1<<31) // ClearRemoteWakeupEnable
// HcRhPortStatus
#define OHCI_PORT_CCS (1<<0) // CurrentConnectStatus
#define OHCI_PORT_PES (1<<1) // PortEnableStatus
@ -190,7 +197,7 @@ class OHCI
// usb packet
USBPacket UsbPacket;
// irq number
int Irq_n;
int IrqNum;
// EOF callback wrapper
static void OHCI_FrameBoundaryWrapper(void* pVoid);
@ -214,8 +221,19 @@ class OHCI
void OHCI_SetInterrupt(uint32_t Value);
//
void OHCI_StopEndpoints();
// update ohci registers during a device attach
void OHCI_Attach(USBPort* Port);
// update ohci registers during a device detach
void OHCI_Detach(USBPort* Port);
// set root hub status
void OHCI_SetHubStatus(uint32_t Value);
// update power related bits in HcRhPortStatus
void OHCI_PortPower(int i, int p);
// set root hub port status
void OHCI_PortSetStatus(int PortNum, uint32_t Value);
// set a flag in a port status register but only set it if the port is connected,
// if not set ConnectStatusChange flag; if flag is enabled return 1
int OHCI_PortSetIfConnected(int i, uint32_t Value);
// register a port with the HC
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask);
@ -224,7 +242,7 @@ class OHCI
// reset a usb port
void USB_PortReset(USBPort* Port);
// a device is attched
void Attach(USBPort* port);
void USB_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
@ -233,6 +251,8 @@ class OHCI
void Wakeup(USBPort* port);
// TODO
void Complete(USBPort* port, USBPacket *p);
// reset a device
void USB_DeviceReset(USBDev* dev);
};
#endif

View File

@ -44,6 +44,7 @@
#define USB_STATE_NOTATTACHED 0
#define USB_STATE_ATTACHED 1
#define USB_STATE_DEFAULT 2
typedef enum USBPacketState {
USB_PACKET_UNDEFINED = 0,
@ -100,7 +101,7 @@ typedef struct _USBDev
int speed;
// Supported speeds, not in info because it may be variable (hostdevs)
int speedmask;
uint8_t addr;
uint8_t Addr; // device address
char product_desc[32];
int auto_attach;
int Attached; // device is attached
@ -108,7 +109,7 @@ typedef struct _USBDev
int32_t State; // current state of device
uint8_t setup_buf[8];
uint8_t data_buf[4096];
int32_t remote_wakeup;
int32_t RemoteWakeup; // wakeup flag
int32_t setup_state;
int32_t setup_len;
int32_t setup_index;