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_HZ 12000000
#define USB_SPEED_LOW 0
#define USB_SPEED_FULL 1
typedef enum _USB_SPEED typedef enum _USB_SPEED
{ {
@ -50,7 +53,7 @@ USB_SPEED;
OHCI::OHCI(int Irq) OHCI::OHCI(int Irq)
{ {
Irq_n = Irq; IrqNum = Irq;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
USB_RegisterPort(&Registers.RhPort[i].UsbPort, i, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); 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(); OHCI_StopEndpoints();
DbgPrintf("Ohci: Reset event.\n"); DbgPrintf("Ohci: Reset mode event.\n");
} }
void OHCI::OHCI_BusStart() 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) // 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); pEOFtimer = Timer_Create(OHCI_FrameBoundaryWrapper, this, 50);
DbgPrintf("Ohci: Operational event\n"); DbgPrintf("Ohci: Operational mode event\n");
// SOF event // SOF event
OHCI_SOF(); OHCI_SOF();
@ -163,11 +166,11 @@ void OHCI::OHCI_ChangeState(uint32_t Value)
case Suspend: case Suspend:
OHCI_BusStop(); OHCI_BusStop();
DbgPrintf("Ohci: Suspend event\n"); DbgPrintf("Ohci: Suspend mode event\n");
break; break;
case Resume: case Resume:
DbgPrintf("Ohci: Resume event\n"); DbgPrintf("Ohci: Resume mode event\n");
break; break;
case Reset: case Reset:
@ -175,7 +178,7 @@ void OHCI::OHCI_ChangeState(uint32_t Value)
break; break;
default: 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; break;
case 20: // HcRhStatus case 20: // HcRhStatus
// TODO OHCI_SetHubStatus(Value);
break; break;
case 21: // RhPort 0 case 21: // RhPort 0
// TODO OHCI_PortSetStatus(0, Value);
break; break;
case 22: // RhPort 1 case 22: // RhPort 1
// TODO OHCI_PortSetStatus(1, Value);
break; break;
default: default:
@ -430,9 +433,9 @@ void OHCI::OHCI_WriteRegister(xbaddr Addr, uint32_t Value)
void OHCI::OHCI_UpdateInterrupt() void OHCI::OHCI_UpdateInterrupt()
{ {
if ((Registers.HcInterrupt & OHCI_INTR_MIE) && (Registers.HcInterruptStatus & Registers.HcInterrupt)) { 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) 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) void OHCI::OHCI_Detach(USBPort* Port)
{ {
OHCIPort* port = &Registers.RhPort[Port->PortIndex]; 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) void OHCI::USB_RegisterPort(USBPort* Port, int Index, int SpeedMask)
{ {
Port->PortIndex = Index; Port->PortIndex = Index;
@ -506,8 +664,8 @@ void OHCI::USB_PortReset(USBPort* Port)
assert(dev != nullptr); assert(dev != nullptr);
USB_Detach(Port); USB_Detach(Port);
usb_attach(port); USB_Attach(Port);
usb_device_reset(dev); USB_DeviceReset(dev);
} }
void OHCI::USB_Detach(USBPort* Port) void OHCI::USB_Detach(USBPort* Port)
@ -519,3 +677,27 @@ void OHCI::USB_Detach(USBPort* Port)
OHCI_Detach(Port); OHCI_Detach(Port);
dev->State = USB_STATE_NOTATTACHED; 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_DT (1<<10) // DeviceType
#define OHCI_RHA_OCPM (1<<11) // OverCurrentProtectionMode #define OHCI_RHA_OCPM (1<<11) // OverCurrentProtectionMode
#define OHCI_RHA_NOCP (1<<12) // NoOverCurrentProtection #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 // HcRhPortStatus
#define OHCI_PORT_CCS (1<<0) // CurrentConnectStatus #define OHCI_PORT_CCS (1<<0) // CurrentConnectStatus
#define OHCI_PORT_PES (1<<1) // PortEnableStatus #define OHCI_PORT_PES (1<<1) // PortEnableStatus
@ -190,7 +197,7 @@ class OHCI
// usb packet // usb packet
USBPacket UsbPacket; USBPacket UsbPacket;
// irq number // irq number
int Irq_n; int IrqNum;
// EOF callback wrapper // EOF callback wrapper
static void OHCI_FrameBoundaryWrapper(void* pVoid); static void OHCI_FrameBoundaryWrapper(void* pVoid);
@ -214,8 +221,19 @@ class OHCI
void OHCI_SetInterrupt(uint32_t Value); void OHCI_SetInterrupt(uint32_t Value);
// //
void OHCI_StopEndpoints(); void OHCI_StopEndpoints();
// update ohci registers during a device attach
void OHCI_Attach(USBPort* Port);
// update ohci registers during a device detach // update ohci registers during a device detach
void OHCI_Detach(USBPort* Port); 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 // register a port with the HC
void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask); void USB_RegisterPort(USBPort* Port, int Index, int SpeedMask);
@ -224,7 +242,7 @@ class OHCI
// reset a usb port // reset a usb port
void USB_PortReset(USBPort* Port); void USB_PortReset(USBPort* Port);
// a device is attched // a device is attched
void Attach(USBPort* port); void USB_Attach(USBPort* port);
// a device is detached // a device is detached
void USB_Detach(USBPort* port); void USB_Detach(USBPort* port);
// a device downstream from the device attached to the port (attached through a hub) is detached // 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); void Wakeup(USBPort* port);
// TODO // TODO
void Complete(USBPort* port, USBPacket *p); void Complete(USBPort* port, USBPacket *p);
// reset a device
void USB_DeviceReset(USBDev* dev);
}; };
#endif #endif

View File

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