[USBEHCI_NEW]

- Move USB_REQUEST_SET_FEATURE / USB_REQUEST_GET_FEATURE flags to header file.
- Remove QueueHead and Descriptor creation as its in UsbRequest.
- Move DMACommon Buffer allocation back to UsbHardwareDevice class.
- Implement Port Handling functions GetPortStatus, ClearPortStatus and SetPortFeature.
- Implement GetUSBQueue for returning pointer to UsbQueue and GetDMA to return DMAMemoryManager.
- Fix a typo in one of the defines for Port Register Flags.

svn path=/branches/usb-bringup/; revision=51397
This commit is contained in:
Michael Martin 2011-04-19 06:56:30 +00:00
parent 3ac2c07f55
commit c3d1d6fda9
5 changed files with 220 additions and 164 deletions

View file

@ -52,7 +52,7 @@ public:
NTSTATUS PnpStop(void);
NTSTATUS HandlePower(PIRP Irp);
NTSTATUS GetDeviceDetails(PUSHORT VendorId, PUSHORT DeviceId, PULONG NumberOfPorts, PULONG Speed);
NTSTATUS GetDmaAdapter(OUT PDMA_ADAPTER AdapterObject);
NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager);
NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue);
NTSTATUS StartController();
@ -60,6 +60,10 @@ public:
NTSTATUS ResetController();
NTSTATUS ResetPort(ULONG PortIndex);
NTSTATUS GetPortStatus(ULONG PortId, OUT USHORT *PortStatus, OUT USHORT *PortChange);
NTSTATUS ClearPortStatus(ULONG PortId, ULONG Status);
NTSTATUS SetPortFeature(ULONG PortId, ULONG Feature);
VOID SetAsyncListRegister(ULONG PhysicalAddress);
VOID SetPeriodicListRegister(ULONG PhysicalAddress);
@ -85,6 +89,8 @@ protected:
KSPIN_LOCK m_Lock;
PKINTERRUPT m_Interrupt;
KDPC m_IntDpcObject;
PVOID VirtualBase;
PHYSICAL_ADDRESS PhysicalAddress;
PULONG m_Base;
PDMA_ADAPTER m_Adapter;
ULONG m_MapRegisters;
@ -92,7 +98,7 @@ protected:
USHORT m_VendorID;
USHORT m_DeviceID;
PUSBQUEUE m_UsbQueue;
PDMAMEMORYMANAGER m_MemoryManager;
VOID SetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
VOID GetCommandRegister(PEHCI_USBCMD_CONTENT UsbCmd);
ULONG EHCI_READ_REGISTER_ULONG(ULONG Offset);
@ -132,6 +138,16 @@ CUSBHardwareDevice::Initialize(
DPRINT1("CUSBHardwareDevice::Initialize\n");
//
// Create DMAMemoryManager for use with QueueHeads and Transfer Descriptors.
//
Status = CreateDMAMemoryManager(&m_MemoryManager);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create DMAMemoryManager Object\n");
return Status;
}
//
// Create the UsbQueue class that will handle the Asynchronous and Periodic Schedules
//
@ -142,6 +158,16 @@ CUSBHardwareDevice::Initialize(
return Status;
}
//
// Initialize the DMAMemoryManager
//
Status = m_MemoryManager->Initialize(this, &m_Lock, PAGE_SIZE * 4, VirtualBase, PhysicalAddress, 32);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to initialize the DMAMemoryManager\n");
return Status;
}
//
// store device objects
//
@ -336,6 +362,19 @@ CUSBHardwareDevice::PnpStart(
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Create Common Buffer
//
VirtualBase = m_Adapter->DmaOperations->AllocateCommonBuffer(m_Adapter,
PAGE_SIZE * 4,
&PhysicalAddress,
FALSE);
if (!VirtualBase)
{
DPRINT1("Failed to allocate a common buffer\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Stop the controller before modifying schedules
//
@ -395,14 +434,26 @@ CUSBHardwareDevice::GetDeviceDetails(
return STATUS_SUCCESS;
}
NTSTATUS CUSBHardwareDevice::GetDMA(
OUT struct IDMAMemoryManager **OutDMAMemoryManager)
{
if (!m_MemoryManager)
return STATUS_UNSUCCESSFUL;
*OutDMAMemoryManager = m_MemoryManager;
return STATUS_SUCCESS;
}
NTSTATUS
CUSBHardwareDevice::GetUSBQueue(
OUT struct IUSBQueue **OutUsbQueue)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
if (!m_UsbQueue)
return STATUS_UNSUCCESSFUL;
*OutUsbQueue = m_UsbQueue;
return STATUS_SUCCESS;
}
NTSTATUS
CUSBHardwareDevice::StartController(void)
{
@ -589,6 +640,140 @@ CUSBHardwareDevice::ResetPort(
return STATUS_SUCCESS;
}
NTSTATUS CUSBHardwareDevice::GetPortStatus(
ULONG PortId,
OUT USHORT *PortStatus,
OUT USHORT *PortChange)
{
ULONG Value;
USHORT Status = 0, Change = 0;
//
// Get the value of the Port Status and Control Register
//
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
//
// If the PowerPortControl is 0 then host controller does not have power control switches
if (!m_Capabilities.HCSParams.PortPowerControl)
{
Status |= USB_PORT_STATUS_POWER;
}
else
{
// Check the value of PortPower
if (Value & EHCI_PRT_POWER)
{
Status |= USB_PORT_STATUS_POWER;
}
}
// Get Speed. If SlowSpeedLine flag is there then its a slow speed device
if (Value & EHCI_PRT_SLOWSPEEDLINE)
Status |= USB_PORT_STATUS_LOW_SPEED;
else
Status |= USB_PORT_STATUS_HIGH_SPEED;
// Get Connected Status
if (Value & EHCI_PRT_CONNECTED)
Status |= USB_PORT_STATUS_CONNECT;
// Get Enabled Status
if (Value & EHCI_PRT_ENABLED)
Status |= USB_PORT_STATUS_ENABLE;
// Is it suspended?
if (Value & EHCI_PRT_SUSPEND)
Status |= USB_PORT_STATUS_SUSPEND;
// a overcurrent is active?
if (Value & EHCI_PRT_OVERCURRENTACTIVE)
Status |= USB_PORT_STATUS_OVER_CURRENT;
// In a reset state?
if (Value & EHCI_PRT_RESET)
Status |= USB_PORT_STATUS_RESET;
//
// FIXME: Is the Change here correct?
//
if (Value & EHCI_PRT_CONNECTSTATUSCHANGE)
Change |= USB_PORT_STATUS_CONNECT;
if (Value & EHCI_PRT_ENABLEDSTATUSCHANGE)
Change |= USB_PORT_STATUS_ENABLE;
return STATUS_SUCCESS;
}
NTSTATUS CUSBHardwareDevice::ClearPortStatus(
ULONG PortId,
ULONG Status)
{
ULONG Value;
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
if (Status == C_PORT_RESET)
{
if (Value & EHCI_PRT_RESET)
{
Value &= ~EHCI_PRT_RESET;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
KeStallExecutionProcessor(100);
}
}
if (Status == C_PORT_CONNECTION)
{
// FIXME: Make sure its the Connection and Enable Change status.
Value |= EHCI_PRT_CONNECTSTATUSCHANGE;
Value |= EHCI_PRT_ENABLEDSTATUSCHANGE;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
}
return STATUS_SUCCESS;
}
NTSTATUS CUSBHardwareDevice::SetPortFeature(
ULONG PortId,
ULONG Feature)
{
ULONG Value;
Value = EHCI_READ_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId));
if (Feature == PORT_ENABLE)
{
//
// FIXME: EHCI Ports can only be disabled via reset
//
}
if (Feature == PORT_RESET)
{
if (Value & EHCI_PRT_SLOWSPEEDLINE)
{
DPRINT1("Non HighSpeed device. Releasing Ownership\n");
}
//
// Reset and clean enable
//
Value |= EHCI_PRT_RESET;
Value &= ~EHCI_PRT_ENABLED;
EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * PortId), Value);
KeStallExecutionProcessor(100);
}
if (Feature == PORT_POWER)
DPRINT1("Not implemented\n");
return STATUS_SUCCESS;
}
VOID CUSBHardwareDevice::SetAsyncListRegister(ULONG PhysicalAddress)
{
EHCI_WRITE_REGISTER_ULONG(EHCI_ASYNCLISTBASE, PhysicalAddress);
@ -693,12 +878,12 @@ EhciDefferedRoutine(
//
// Device connected or removed
//
if (PortStatus & EHCI_PRT_CONNECTSTATUSCHAGE)
if (PortStatus & EHCI_PRT_CONNECTSTATUSCHANGE)
{
//
// Clear the port change status
//
This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus & EHCI_PRT_CONNECTSTATUSCHAGE);
This->EHCI_WRITE_REGISTER_ULONG(EHCI_PORTSC + (4 * i), PortStatus | EHCI_PRT_CONNECTSTATUSCHANGE);
if (PortStatus & EHCI_PRT_CONNECTED)
{

View file

@ -46,7 +46,7 @@
// Port Register Flags
//
#define EHCI_PRT_CONNECTED 0x01
#define EHCI_PRT_CONNECTSTATUSCHAGE 0x02
#define EHCI_PRT_CONNECTSTATUSCHANGE 0x02
#define EHCI_PRT_ENABLED 0x04
#define EHCI_PRT_ENABLEDSTATUSCHANGE 0x08
#define EHCI_PRT_OVERCURRENTACTIVE 0x10
@ -192,7 +192,7 @@ typedef struct _QUEUE_HEAD
LIST_ENTRY LinkedQueueHeads;
PQUEUE_TRANSFER_DESCRIPTOR TransferDescriptor;
PIRP IrpToComplete;
PMDL MdlToFree;
PMDL Mdl;
PKEVENT Event;
} QUEUE_HEAD, *PQUEUE_HEAD;

View file

@ -157,20 +157,6 @@ const UCHAR ROOTHUB2_ENDPOINT_DESCRIPTOR [] =
0xFF /* bInterval; (255ms -- usb 2.0 spec) */
};
//
// flags for handling USB_REQUEST_SET_FEATURE / USB_REQUEST_GET_FEATURE
//
#define PORT_ENABLE 1
#define PORT_SUSPEND 2
#define PORT_OVER_CURRENT 3
#define PORT_RESET 4
#define PORT_POWER 8
#define C_PORT_CONNECTION 16
#define C_PORT_ENABLE 17
#define C_PORT_SUSPEND 18
#define C_PORT_OVER_CURRENT 19
#define C_PORT_RESET 20
//----------------------------------------------------------------------------------------
NTSTATUS
STDMETHODCALLTYPE

View file

@ -48,14 +48,9 @@ protected:
LONG m_Ref;
KSPIN_LOCK m_Lock;
PDMA_ADAPTER m_Adapter;
PVOID VirtualBase;
PHYSICAL_ADDRESS PhysicalAddress;
PQUEUE_HEAD AsyncQueueHead;
PQUEUE_HEAD PendingQueueHead;
IDMAMemoryManager *m_MemoryManager;
PQUEUE_HEAD CreateQueueHead();
PQUEUE_TRANSFER_DESCRIPTOR CreateDescriptor(UCHAR PIDCode, ULONG TotalBytesToTransfer);
VOID LinkQueueHead(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
VOID UnlinkQueueHead(PQUEUE_HEAD QueueHead);
VOID LinkQueueHeadChain(PQUEUE_HEAD HeadQueueHead, PQUEUE_HEAD NewQueueHead);
@ -87,35 +82,11 @@ CUSBQueue::Initialize(
PDMA_ADAPTER AdapterObject,
IN OPTIONAL PKSPIN_LOCK Lock)
{
NTSTATUS Status;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT1("CUSBQueue::Initialize()\n");
ASSERT(Hardware);
ASSERT(AdapterObject);
//
// Create Common Buffer
//
VirtualBase = AdapterObject->DmaOperations->AllocateCommonBuffer(AdapterObject,
PAGE_SIZE * 4,
&PhysicalAddress,
FALSE);
if (!VirtualBase)
{
DPRINT1("Failed to allocate a common buffer\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Create DMAMemoryManager for use with QueueHeads and Transfer Descriptors.
//
Status = CreateDMAMemoryManager(&m_MemoryManager);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create DMAMemoryManager Object\n");
return Status;
}
//
// initialize device lock
@ -123,46 +94,20 @@ CUSBQueue::Initialize(
KeInitializeSpinLock(&m_Lock);
//
// Initialize the DMAMemoryManager
// FIXME: Need to set AsyncRegister with a QUEUEHEAD
//
Status = m_MemoryManager->Initialize(Hardware, &m_Lock, PAGE_SIZE * 4, VirtualBase, PhysicalAddress, 32);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to initialize the DMAMemoryManager\n");
return Status;
}
//
// Create a QueueHead for use in Async Register
//
AsyncQueueHead = CreateQueueHead();
AsyncQueueHead->HorizontalLinkPointer = AsyncQueueHead->PhysicalAddr | QH_TYPE_QH;
AsyncQueueHead->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
AsyncQueueHead->Token.Bits.InterruptOnComplete = FALSE;
AsyncQueueHead->EndPointCharacteristics.HeadOfReclamation = TRUE;
AsyncQueueHead->Token.Bits.Halted = TRUE;
Hardware->SetAsyncListRegister(AsyncQueueHead->PhysicalAddr);
//
// Create a Unused QueueHead to hold pending QueueHeads
//
PendingQueueHead = CreateQueueHead();
PendingQueueHead->Token.Bits.Halted = TRUE;
//
// Initialize ListHead in QueueHeads
//
InitializeListHead(&AsyncQueueHead->LinkedQueueHeads);
InitializeListHead(&PendingQueueHead->LinkedQueueHeads);
return STATUS_SUCCESS;
return Status;
}
ULONG
CUSBQueue::GetPendingRequestCount()
{
UNIMPLEMENTED
//
// Loop through the pending list and iterrate one for each QueueHead that
// has a IRP to complete.
//
return 0;
}
@ -197,84 +142,6 @@ CUSBQueue::CreateUSBRequest(
return STATUS_NOT_IMPLEMENTED;
}
PQUEUE_HEAD
CUSBQueue::CreateQueueHead()
{
PQUEUE_HEAD QueueHead;
PHYSICAL_ADDRESS PhysicalAddress;
NTSTATUS Status;
//
// Create the QueueHead from Common Buffer
//
Status = m_MemoryManager->Allocate(sizeof(QUEUE_HEAD),
(PVOID*)&QueueHead,
&PhysicalAddress);
if (!NT_SUCCESS(Status))
return NULL;
//
// Initialize default values
//
QueueHead->PhysicalAddr = PhysicalAddress.LowPart;
QueueHead->HorizontalLinkPointer = TERMINATE_POINTER;
QueueHead->AlternateNextPointer = TERMINATE_POINTER;
QueueHead->NextPointer = TERMINATE_POINTER;
// 1 for non high speed, 0 for high speed device
QueueHead->EndPointCharacteristics.ControlEndPointFlag = 0;
QueueHead->EndPointCharacteristics.HeadOfReclamation = FALSE;
QueueHead->EndPointCharacteristics.MaximumPacketLength = 64;
// Set NakCountReload to max value possible
QueueHead->EndPointCharacteristics.NakCountReload = 0xF;
// Get the Initial Data Toggle from the Queue Element Desriptor
QueueHead->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
QueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03;
// Interrupt when QueueHead is processed
QueueHead->Token.Bits.InterruptOnComplete = FALSE;
return QueueHead;
}
PQUEUE_TRANSFER_DESCRIPTOR
CUSBQueue::CreateDescriptor(
UCHAR PIDCode,
ULONG TotalBytesToTransfer)
{
PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
PHYSICAL_ADDRESS PhysicalAddress;
NTSTATUS Status;
//
// Create the Descriptor from Common Buffer
//
Status = m_MemoryManager->Allocate(sizeof(QUEUE_TRANSFER_DESCRIPTOR),
(PVOID*)&Descriptor,
&PhysicalAddress);
if (!NT_SUCCESS(Status))
return NULL;
//
// Set default values
//
Descriptor->NextPointer = TERMINATE_POINTER;
Descriptor->AlternateNextPointer = TERMINATE_POINTER;
Descriptor->Token.Bits.DataToggle = TRUE;
Descriptor->Token.Bits.ErrorCounter = 0x03;
Descriptor->Token.Bits.Active = TRUE;
Descriptor->Token.Bits.PIDCode = PIDCode;
Descriptor->Token.Bits.TotalBytesToTransfer = TotalBytesToTransfer;
Descriptor->PhysicalAddr = PhysicalAddress.LowPart;
return Descriptor;
}
//
// LinkQueueHead - Links one QueueHead to the end of HeadQueueHead list, updating HorizontalLinkPointer.
//

View file

@ -7,6 +7,10 @@
#include <hubbusif.h>
#include <usbbusif.h>
#include <usbioctl.h>
//
// FIXME:
// #include <usbprotocoldefs.h>
//
#include <usb.h>
#include <stdio.h>
#include <wdmguid.h>
@ -21,6 +25,20 @@
#include "interfaces.h"
//
// flags for handling USB_REQUEST_SET_FEATURE / USB_REQUEST_GET_FEATURE
//
#define PORT_ENABLE 1
#define PORT_SUSPEND 2
#define PORT_OVER_CURRENT 3
#define PORT_RESET 4
#define PORT_POWER 8
#define C_PORT_CONNECTION 16
#define C_PORT_ENABLE 17
#define C_PORT_SUSPEND 18
#define C_PORT_OVER_CURRENT 19
#define C_PORT_RESET 20
typedef struct
{
BOOLEAN IsFDO; // is device a FDO or PDO