More usb port stuff
This commit is contained in:
parent
421a5b8754
commit
0fd31a0df6
|
@ -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)
|
||||
|
@ -519,3 +677,27 @@ void OHCI::USB_Detach(USBPort* Port)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue