#define INITGUID
#include "usbehci.h"
+#include "hardware.h"
+
+BOOLEAN
+NTAPI
+InterruptServiceRoutine(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext);
class CUSBHardwareDevice : public IUSBHardwareDevice
{
NTSTATUS GetDeviceDetails(PULONG VendorId, PULONG DeviceId, PULONG NumberOfPorts, PULONG Speed);
NTSTATUS GetDmaMemoryManager(OUT struct IDMAMemoryManager **OutMemoryManager);
NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue);
+ NTSTATUS StartController();
+ NTSTATUS StopController();
NTSTATUS ResetController();
NTSTATUS ResetPort(ULONG PortIndex);
KIRQL AcquireDeviceLock(void);
PULONG m_Base;
PDMA_ADAPTER m_Adapter;
ULONG m_MapRegisters;
+ PQUEUE_HEAD AsyncListQueueHead;
+ EHCI_CAPS m_Capabilities;
+
+ VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
+ VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
+ VOID SetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts);
+ VOID GetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts);
+ //VOID SetPortRegister(PEHCI_USBPORTSC_CONTENT UsbPort);
+ //VOID GetPortRegister(PEHCI_USBPORTSC_CONTENT UsbPort);
+ ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
+ ULONG EHCI_READ_REGISTER_USHORT(ULONG Offset);
+ ULONG EHCI_READ_REGISTER_UCHAR(ULONG Offset);
+ VOID EHCI_WRITE_REGISTER_ULONG(ULONG Offset, ULONG Value);
+ VOID EHCI_WRITE_REGISTER_USHORT(ULONG Offset, ULONG Value);
+ VOID EHCI_WRITE_REGISTER_UCHAR(ULONG Offset, ULONG Value);
};
//=================================================================================================
return STATUS_SUCCESS;
}
+VOID
+CUSBHardwareDevice::SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd)
+{
+ PULONG Register;
+ Register = (PULONG)UsbCmd;
+ WRITE_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBCMD), *Register);
+}
+
+VOID
+CUSBHardwareDevice::GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd)
+{
+ PULONG Register;
+ Register = (PULONG)UsbCmd;
+ *Register = READ_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBCMD));
+}
+
+
+VOID
+CUSBHardwareDevice::SetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts)
+{
+ PULONG Register;
+ Register = (PULONG)UsbSts;
+ WRITE_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBSTS), *Register);
+}
+
+VOID
+CUSBHardwareDevice::GetStatusRegister(PEHCI_USBSTS_CONTENT UsbSts)
+{
+ PULONG CmdRegister;
+ CmdRegister = (PULONG)UsbSts;
+ *CmdRegister = READ_REGISTER_ULONG((PULONG)((ULONG)m_Base + EHCI_USBSTS));
+}
+
+ULONG
+CUSBHardwareDevice::EHCI_READ_REGISTER_ULONG(ULONG Offset)
+{
+ return READ_REGISTER_ULONG((PULONG)((ULONG)m_Base + Offset));
+}
+
+ULONG
+CUSBHardwareDevice::EHCI_READ_REGISTER_USHORT(ULONG Offset)
+{
+ return READ_REGISTER_USHORT((PUSHORT)((ULONG)m_Base + Offset));
+}
+
+ULONG
+CUSBHardwareDevice::EHCI_READ_REGISTER_UCHAR(ULONG Offset)
+{
+ return READ_REGISTER_UCHAR((PUCHAR)((ULONG)m_Base + Offset));
+}
+
+VOID
+CUSBHardwareDevice::EHCI_WRITE_REGISTER_ULONG(ULONG Offset, ULONG Value)
+{
+ WRITE_REGISTER_ULONG((PULONG)((ULONG)m_Base + Offset), Value);
+}
+
+VOID
+CUSBHardwareDevice::EHCI_WRITE_REGISTER_USHORT(ULONG Offset, ULONG Value)
+{
+ WRITE_REGISTER_USHORT((PUSHORT)((ULONG)m_Base + Offset), Value);
+}
+
+VOID
+CUSBHardwareDevice::EHCI_WRITE_REGISTER_UCHAR(ULONG Offset, ULONG Value)
+{
+ WRITE_REGISTER_UCHAR((PUCHAR)((ULONG)m_Base + Offset), Value);
+}
NTSTATUS
CUSBHardwareDevice::PnpStart(
PCM_RESOURCE_LIST RawResources,
PCM_RESOURCE_LIST TranslatedResources)
{
- ULONG Index;
+ ULONG Index, Count;
PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
DEVICE_DESCRIPTION DeviceDescription;
PVOID ResourceBase;
}
//
- //FIXME: query capabilities and update m_Base
+ // Get controllers capabilities
+ //
+ m_Capabilities.Length = READ_REGISTER_UCHAR((PUCHAR)ResourceBase);
+ m_Capabilities.HCIVersion = READ_REGISTER_USHORT((PUSHORT)((ULONG)ResourceBase + 2));
+ m_Capabilities.HCSParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 4));
+ m_Capabilities.HCCParamsLong = READ_REGISTER_ULONG((PULONG)((ULONG)ResourceBase + 8));
+
+ DPRINT1("Controller has %d Ports\n", m_Capabilities.HCSParams.PortCount);
+ if (m_Capabilities.HCSParams.PortRouteRules)
+ {
+ for (Count = 0; Count < m_Capabilities.HCSParams.PortCount; Count++)
+ {
+ m_Capabilities.PortRoute[Count] = READ_REGISTER_UCHAR((PUCHAR)(ULONG)ResourceBase + 12 + Count);
+ }
+ }
+
+ //
+ // Set m_Base to the address of Operational Register Space
//
+ m_Base = (PULONG)((ULONG)ResourceBase + m_Capabilities.Length);
break;
}
}
return STATUS_INSUFFICIENT_RESOURCES;
}
- return STATUS_SUCCESS;
+ //
+ // FIXME: Create a QueueHead that will always be the address of the AsyncList
+ //
+ AsyncListQueueHead = NULL;
+
+ //
+ // Start the controller
+ //
+ DPRINT1("Starting Controller\n");
+ return StartController();
}
NTSTATUS
return STATUS_NOT_IMPLEMENTED;
}
+NTSTATUS
+CUSBHardwareDevice::StartController(void)
+{
+ EHCI_USBCMD_CONTENT UsbCmd;
+ EHCI_USBSTS_CONTENT UsbSts;
+ LONG FailSafe;
+
+ //
+ // Stop the controller if its running
+ //
+ GetStatusRegister(&UsbSts);
+ if (UsbSts.HCHalted)
+ StopController();
+
+ //
+ // Reset the device. Bit is set to 0 on completion.
+ //
+ SetCommandRegister(&UsbCmd);
+ UsbCmd.HCReset = TRUE;
+ SetCommandRegister(&UsbCmd);
+
+ //
+ // Check that the controller reset
+ //
+ for (FailSafe = 100; FailSafe > 1; FailSafe--)
+ {
+ KeStallExecutionProcessor(10);
+ GetCommandRegister(&UsbCmd);
+ if (!UsbCmd.HCReset)
+ {
+ break;
+ }
+ }
+
+ //
+ // If the controller did not reset then fail
+ //
+ if (UsbCmd.HCReset)
+ {
+ DPRINT1("EHCI ERROR: Controller failed to reset. Hardware problem!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Disable Interrupts and clear status
+ //
+ EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, 0);
+ EHCI_WRITE_REGISTER_ULONG(EHCI_USBSTS, 0x0000001f);
+
+ //
+ // FIXME: Assign the AsyncList Register
+ //
+
+ //
+ // Set Schedules to Enable and Interrupt Threshold to 1ms.
+ //
+ GetCommandRegister(&UsbCmd);
+ UsbCmd.PeriodicEnable = FALSE;
+ UsbCmd.AsyncEnable = FALSE; //FIXME: Need USB Memory Manager
+
+ UsbCmd.IntThreshold = 1;
+ // FIXME: Set framlistsize when periodic is implemented.
+ SetCommandRegister(&UsbCmd);
+
+ //
+ // Enable Interrupts and start execution
+ //
+ EHCI_WRITE_REGISTER_ULONG(EHCI_USBINTR, EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
+ /*| EHCI_USBINTR_FLROVR*/ | EHCI_USBINTR_PC);
+
+ UsbCmd.Run = TRUE;
+ SetCommandRegister(&UsbCmd);
+
+ //
+ // Wait for execution to start
+ //
+ for (FailSafe = 100; FailSafe > 1; FailSafe--)
+ {
+ KeStallExecutionProcessor(10);
+ GetStatusRegister(&UsbSts);
+
+ if (!UsbSts.HCHalted)
+ {
+ break;
+ }
+ }
+
+ if (!UsbSts.HCHalted)
+ {
+ DPRINT1("Could not start execution on the controller\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Set port routing to EHCI controller
+ //
+ EHCI_WRITE_REGISTER_ULONG(EHCI_CONFIGFLAG, 1);
+ DPRINT1("EHCI Started!\n");
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CUSBHardwareDevice::StopController(void)
+{
+ EHCI_USBCMD_CONTENT UsbCmd;
+ EHCI_USBSTS_CONTENT UsbSts;
+ LONG FailSafe;
+
+ //
+ // Disable Interrupts and stop execution
+ EHCI_WRITE_REGISTER_ULONG (EHCI_USBINTR, 0);
+
+ GetCommandRegister(&UsbCmd);
+ UsbCmd.Run = FALSE;
+ SetCommandRegister(&UsbCmd);
+
+ for (FailSafe = 100; FailSafe > 1; FailSafe--)
+ {
+ KeStallExecutionProcessor(10);
+ GetStatusRegister(&UsbSts);
+ if (UsbSts.HCHalted)
+ {
+ break;
+ }
+ }
+
+ if (!UsbSts.HCHalted)
+ {
+ DPRINT1("EHCI ERROR: Controller is not responding to Stop request!\n");
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
NTSTATUS
CUSBHardwareDevice::ResetController(void)
{
PUSBHARDWAREDEVICE This;
- This = new(NonPagedPool, 0) CUSBHardwareDevice(0);
+ This = new(NonPagedPool, TAG_USBEHCI) CUSBHardwareDevice(0);
+
if (!This)
return STATUS_INSUFFICIENT_RESOURCES;