// get frame interval
//
FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET));
+ FrameInterval = ((FrameInterval & OHCI_FRAME_INTERVAL_TOGGLE) ^ OHCI_FRAME_INTERVAL_TOGGLE);
DPRINT1("FrameInterval %x IntervalValue %x\n", FrameInterval, m_IntervalValue);
FrameInterval |= OHCI_FSMPS(m_IntervalValue) | m_IntervalValue;
DPRINT1("FrameInterval %x\n", FrameInterval);
NTSTATUS
CUSBHardwareDevice::StopController(void)
{
- ULONG Control, Reset;
+ ULONG Control, Reset, Status;
ULONG Index, FrameInterval;
//
- // first turn off all interrupts
+ // alignment check
//
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_INTERRUPT_DISABLE_OFFSET), OHCI_ALL_INTERRUPTS);
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET, 0xFFFFFFFF);
+ Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_HCCA_OFFSET));
+ DPRINT1("HcHCCA Alignment %x\n", Control);
+ ASSERT((Control & 0xFFFFFFF0) == 0xFFFFFFF0);
//
// check context
//
Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
- //
- // FIXME: support routing
- //
- ASSERT((Control & OHCI_INTERRUPT_ROUTING) == 0);
+ if ((Control & OHCI_INTERRUPT_ROUTING))
+ {
+ //
+ // read command status
+ //
+ Status = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET));
- //
- // have a break
- //
- KeStallExecutionProcessor(100);
+ //
+ // change ownership
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Status | OHCI_OWNERSHIP_CHANGE_REQUEST);
+ for(Index = 0; Index < 100; Index++)
+ {
+ //
+ // wait a bit
+ //
+ KeStallExecutionProcessor(100);
- //
- // some controllers also depend on this
- //
- WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET);
+ //
+ // check control
+ //
+ Control = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET));
+ if (!(Control & OHCI_INTERRUPT_ROUTING))
+ {
+ //
+ // acquired ownership
+ //
+ break;
+ }
+ }
- //
- // wait a bit
- //
- KeStallExecutionProcessor(100);
+ //
+ // if the ownership is still not changed, perform reset
+ //
+ if (Control & OHCI_INTERRUPT_ROUTING)
+ {
+ DPRINT1("SMM not responding\n");
+ }
+ else
+ {
+ DPRINT1("SMM has given up ownership\n");
+ }
+ }
+ else
+ {
+ //
+ // read contents of control register
+ //
+ Control = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET)) & OHCI_HC_FUNCTIONAL_STATE_MASK);
+ DPRINT1("Controller State %x\n", Control);
+
+ if (Control != OHCI_HC_FUNCTIONAL_STATE_RESET)
+ {
+ //
+ // OHCI 5.1.1.3.4, no SMM, BIOS active
+ //
+ if (Control != OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL)
+ {
+ //
+ // lets resume
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESUME);
+ Index = 0;
+ do
+ {
+ //
+ // wait untill its resumed
+ //
+ KeStallExecutionProcessor(10);
+
+ //
+ // check control register
+ //
+ Control = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET)) & OHCI_HC_FUNCTIONAL_STATE_MASK);
+ if (Control & OHCI_HC_FUNCTIONAL_STATE_RESUME)
+ {
+ //
+ // it has resumed
+ //
+ break;
+ }
+
+ //
+ // check for time outs
+ //
+ Index++;
+ if(Index > 100)
+ {
+ DPRINT1("Failed to resume controller\n");
+ break;
+ }
+ }while(TRUE);
+ }
+ }
+ else
+ {
+ //
+ // 5.1.1.3.5 OHCI, no SMM, no BIOS
+ //
+ Index = 0;
+
+ //
+ // some controllers also depend on this
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET), OHCI_HC_FUNCTIONAL_STATE_RESET);
+ do
+ {
+ //
+ // wait untill its reset
+ //
+ KeStallExecutionProcessor(10);
+
+ //
+ // check control register
+ //
+ Control = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_OFFSET)) & OHCI_HC_FUNCTIONAL_STATE_MASK);
+ if (Control == OHCI_HC_FUNCTIONAL_STATE_RESET)
+ {
+ //
+ // it has reset
+ //
+ break;
+ }
+
+ //
+ // check for time outs
+ //
+ Index++;
+ if(Index > 100)
+ {
+ DPRINT1("Failed to reset controller\n");
+ break;
+ }
+
+ }while(TRUE);
+ }
+ }
//
// read from interval
//
if ((Reset & OHCI_HOST_CONTROLLER_RESET) == 0)
{
+ //
+ // restore the frame interval register
+ //
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET), FrameInterval);
+
//
// controller completed reset
//
OUT USHORT *PortStatus,
OUT USHORT *PortChange)
{
+ ULONG Value;
+
+ if (PortId > m_NumberOfPorts)
+ return STATUS_UNSUCCESSFUL;
+
+ // init result variables
+ *PortStatus = 0;
+ *PortChange = 0;
+
//
- // FIXME: should read status from hardware
+ // read port status
//
- *PortStatus = m_PortStatus[PortId].PortStatus;
- *PortChange = m_PortStatus[PortId].PortChange;
+ Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_RH_PORT_STATUS(PortId)));
+ DPRINT("GetPortStatus PortId %x Value %x\n", PortId, Value);
+
+
+ // connected
+ if (Value & OHCI_RH_PORTSTATUS_CCS)
+ *PortStatus |= USB_PORT_STATUS_CONNECT;
+
+ // did a device connect?
+ if (Value & OHCI_RH_PORTSTATUS_CSC)
+ *PortChange |= USB_PORT_STATUS_CONNECT;
+
+ // port enabled
+ if (Value & OHCI_RH_PORTSTATUS_PES)
+ *PortStatus |= USB_PORT_STATUS_ENABLE;
+
+ // port enabled
+ if (Value & OHCI_RH_PORTSTATUS_PESC)
+ *PortChange |= USB_PORT_STATUS_ENABLE;
+
+ // port suspend
+ if (Value & OHCI_RH_PORTSTATUS_PSS)
+ *PortStatus |= USB_PORT_STATUS_SUSPEND;
+
+ // port suspend
+ if (Value & OHCI_RH_PORTSTATUS_PSSC)
+ *PortChange |= USB_PORT_STATUS_ENABLE;
+
+ // port reset
+ if (Value & OHCI_RH_PORTSTATUS_PSS)
+ *PortStatus |= USB_PORT_STATUS_RESET;
+
+ // port reset
+ if (Value & OHCI_RH_PORTSTATUS_PRSC)
+ *PortChange |= USB_PORT_STATUS_RESET;
+
return STATUS_SUCCESS;
}
//
This->m_PortStatus[Index].PortStatus |= USB_PORT_STATUS_LOW_SPEED;
}
-
- //
- // is there a status change callback
- //
- if (This->m_SCECallBack != NULL)
- {
- //
- // queue work item for processing
- //
- ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue);
- }
}
else
{
// device disconnected
//
DPRINT1("Device disconnected at Port %x\n", Index);
+
+ //
+ // update port status flags
+ //
+ This->m_PortStatus[Index].PortStatus &= ~USB_PORT_STATUS_LOW_SPEED;
+ This->m_PortStatus[Index].PortStatus &= ~USB_PORT_STATUS_CONNECT;
+ This->m_PortStatus[Index].PortChange |= USB_PORT_STATUS_CONNECT;
+ }
+
+ //
+ // is there a status change callback
+ //
+ if (This->m_SCECallBack != NULL)
+ {
+ //
+ // queue work item for processing
+ //
+ ExQueueWorkItem(&This->m_StatusChangeWorkItem, DelayedWorkQueue);
}
}
}