mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
[USBOHCI]
- Set up periodic threshold (90 %) - Add function to retrieve interrupt endpoints - Add function to retrieve specific descriptors from interface. These are used by HID devices such as mice / keyboards - Add function to retrieve interrupt interval - Enqueue all endpoint descriptors at the end of the associated queue - Only notify hardware of insertion when it is an bulk / control request - Scan interrupt endpoint list to find the completed transfer descriptor - Add debugging function to print out linked endpoint descriptors - Interrupt transfers are now implemented. - Tested in Windows XP SP3 + Vbox 4.04 + Microsoft 5-Button Mouse. The HID mouse installs, initializes and starts up. Unfortunately the mouse does not work as expected yet svn path=/branches/usb-bringup/; revision=51922
This commit is contained in:
parent
667b425b6c
commit
9aff3e967c
6 changed files with 297 additions and 30 deletions
|
@ -61,6 +61,7 @@ public:
|
||||||
NTSTATUS GetDeviceDetails(PUSHORT VendorId, PUSHORT DeviceId, PULONG NumberOfPorts, PULONG Speed);
|
NTSTATUS GetDeviceDetails(PUSHORT VendorId, PUSHORT DeviceId, PULONG NumberOfPorts, PULONG Speed);
|
||||||
NTSTATUS GetBulkHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
|
NTSTATUS GetBulkHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
|
||||||
NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
|
NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
|
||||||
|
NTSTATUS GetInterruptEndpointDescriptors(struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor);
|
||||||
VOID HeadEndpointDescriptorModified(ULONG HeadType);
|
VOID HeadEndpointDescriptorModified(ULONG HeadType);
|
||||||
|
|
||||||
NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager);
|
NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager);
|
||||||
|
@ -113,16 +114,16 @@ protected:
|
||||||
PHYSICAL_ADDRESS m_HCCAPhysicalAddress; // hcca physical address
|
PHYSICAL_ADDRESS m_HCCAPhysicalAddress; // hcca physical address
|
||||||
POHCI_ENDPOINT_DESCRIPTOR m_ControlEndpointDescriptor; // dummy control endpoint descriptor
|
POHCI_ENDPOINT_DESCRIPTOR m_ControlEndpointDescriptor; // dummy control endpoint descriptor
|
||||||
POHCI_ENDPOINT_DESCRIPTOR m_BulkEndpointDescriptor; // dummy control endpoint descriptor
|
POHCI_ENDPOINT_DESCRIPTOR m_BulkEndpointDescriptor; // dummy control endpoint descriptor
|
||||||
POHCI_ENDPOINT_DESCRIPTOR m_IsoEndpointDescriptor; // iso endpoint descriptor
|
POHCI_ENDPOINT_DESCRIPTOR m_IsoEndpointDescriptor; // iso endpoint descriptor
|
||||||
POHCI_ENDPOINT_DESCRIPTOR m_InterruptEndpoints[OHCI_STATIC_ENDPOINT_COUNT]; // endpoints for interrupt / iso transfers
|
POHCI_ENDPOINT_DESCRIPTOR m_InterruptEndpoints[OHCI_STATIC_ENDPOINT_COUNT]; // endpoints for interrupt / iso transfers
|
||||||
ULONG m_NumberOfPorts; // number of ports
|
ULONG m_NumberOfPorts; // number of ports
|
||||||
OHCI_PORT_STATUS m_PortStatus[OHCI_MAX_PORT_COUNT]; // port change status
|
OHCI_PORT_STATUS m_PortStatus[OHCI_MAX_PORT_COUNT]; // port change status
|
||||||
PDMAMEMORYMANAGER m_MemoryManager; // memory manager
|
PDMAMEMORYMANAGER m_MemoryManager; // memory manager
|
||||||
HD_INIT_CALLBACK* m_SCECallBack; // status change callback routine
|
HD_INIT_CALLBACK* m_SCECallBack; // status change callback routine
|
||||||
PVOID m_SCEContext; // status change callback routine context
|
PVOID m_SCEContext; // status change callback routine context
|
||||||
BOOLEAN m_DoorBellRingInProgress; // door bell ring in progress
|
|
||||||
WORK_QUEUE_ITEM m_StatusChangeWorkItem; // work item for status change callback
|
WORK_QUEUE_ITEM m_StatusChangeWorkItem; // work item for status change callback
|
||||||
ULONG m_SyncFramePhysAddr; // periodic frame list physical address
|
ULONG m_SyncFramePhysAddr; // periodic frame list physical address
|
||||||
|
ULONG m_IntervalValue; // periodic interval value
|
||||||
};
|
};
|
||||||
|
|
||||||
//=================================================================================================
|
//=================================================================================================
|
||||||
|
@ -489,7 +490,7 @@ CUSBHardwareDevice::GetUSBQueue(
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CUSBHardwareDevice::StartController(void)
|
CUSBHardwareDevice::StartController(void)
|
||||||
{
|
{
|
||||||
ULONG Control, NumberOfPorts, Index, Descriptor, FrameInterval, Periodic, IntervalValue;
|
ULONG Control, NumberOfPorts, Index, Descriptor, FrameInterval, Periodic;
|
||||||
|
|
||||||
//
|
//
|
||||||
// first write address of HCCA
|
// first write address of HCCA
|
||||||
|
@ -545,16 +546,19 @@ CUSBHardwareDevice::StartController(void)
|
||||||
//
|
//
|
||||||
// get frame interval
|
// get frame interval
|
||||||
//
|
//
|
||||||
//FrameInterval = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET)) & OHCI_FRAME_INTERVAL_TOGGLE) ^ OHCI_FRAME_INTERVAL_TOGGLE;
|
FrameInterval = (READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET)) & OHCI_FRAME_INTERVAL_TOGGLE) ^ OHCI_FRAME_INTERVAL_TOGGLE;
|
||||||
//FrameInterval |= OHCI_FSMPS(IntervalValue) | IntervalValue;
|
FrameInterval |= OHCI_FSMPS(m_IntervalValue) | m_IntervalValue;
|
||||||
|
|
||||||
//
|
//
|
||||||
// write frame interval
|
// write frame interval
|
||||||
//
|
//
|
||||||
//WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET), FrameInterval);
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET), FrameInterval);
|
||||||
// 90% periodic
|
|
||||||
//Periodic = OHCI_PERIODIC(intervalValue);
|
//
|
||||||
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + 0x40 /*OHCI_PERIODIC_START_OFFSET*/), 0x3E67);
|
// 90 % periodic
|
||||||
|
//
|
||||||
|
Periodic = OHCI_PERIODIC(m_IntervalValue);
|
||||||
|
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_PERIODIC_START_OFFSET), Periodic);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -686,6 +690,14 @@ CUSBHardwareDevice::GetBulkHeadEndpointDescriptor(
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBHardwareDevice::GetInterruptEndpointDescriptors(
|
||||||
|
struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor)
|
||||||
|
{
|
||||||
|
*OutDescriptor = m_InterruptEndpoints;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
CUSBHardwareDevice::HeadEndpointDescriptorModified(
|
CUSBHardwareDevice::HeadEndpointDescriptorModified(
|
||||||
ULONG Type)
|
ULONG Type)
|
||||||
|
@ -846,7 +858,7 @@ NTSTATUS
|
||||||
CUSBHardwareDevice::StopController(void)
|
CUSBHardwareDevice::StopController(void)
|
||||||
{
|
{
|
||||||
ULONG Control, Reset;
|
ULONG Control, Reset;
|
||||||
ULONG Index;
|
ULONG Index, FrameInterval;
|
||||||
|
|
||||||
//
|
//
|
||||||
// first turn off all interrupts
|
// first turn off all interrupts
|
||||||
|
@ -878,6 +890,16 @@ CUSBHardwareDevice::StopController(void)
|
||||||
//
|
//
|
||||||
KeStallExecutionProcessor(100);
|
KeStallExecutionProcessor(100);
|
||||||
|
|
||||||
|
//
|
||||||
|
// read from interval
|
||||||
|
//
|
||||||
|
FrameInterval = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_FRAME_INTERVAL_OFFSET));
|
||||||
|
|
||||||
|
//
|
||||||
|
// store interval value for later
|
||||||
|
//
|
||||||
|
m_IntervalValue = OHCI_GET_INTERVAL_VALUE(FrameInterval);
|
||||||
|
|
||||||
//
|
//
|
||||||
// now reset controller
|
// now reset controller
|
||||||
//
|
//
|
||||||
|
|
|
@ -90,6 +90,19 @@
|
||||||
#define OHCI_RH_NO_OVER_CURRENT_PROTECTION 0x1000
|
#define OHCI_RH_NO_OVER_CURRENT_PROTECTION 0x1000
|
||||||
#define OHCI_RH_GET_POWER_ON_TO_POWER_GOOD_TIME(s) ((s) >> 24)
|
#define OHCI_RH_GET_POWER_ON_TO_POWER_GOOD_TIME(s) ((s) >> 24)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Frame interval register (section 7.3.1)
|
||||||
|
//
|
||||||
|
#define OHCI_FRAME_INTERVAL_OFFSET 0x34
|
||||||
|
#define OHCI_GET_INTERVAL_VALUE(s) ((s) & 0x3fff)
|
||||||
|
#define OHCI_GET_FS_LARGEST_DATA_PACKET(s) (((s) >> 16) & 0x7fff)
|
||||||
|
#define OHCI_FRAME_INTERVAL_TOGGLE 0x80000000
|
||||||
|
|
||||||
|
//
|
||||||
|
// periodic start register
|
||||||
|
//
|
||||||
|
#define OHCI_PERIODIC_START_OFFSET 0x40
|
||||||
|
#define OHCI_PERIODIC(i) ((i) * 9 / 10)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Root Hub Descriptor B register (section 7.4.2)
|
// Root Hub Descriptor B register (section 7.4.2)
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
VOID SetNotification(PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine);
|
VOID SetNotification(PVOID CallbackContext, PRH_INIT_CALLBACK CallbackRoutine);
|
||||||
// internal ioctl routines
|
// internal ioctl routines
|
||||||
NTSTATUS HandleGetDescriptor(IN OUT PIRP Irp, PURB Urb);
|
NTSTATUS HandleGetDescriptor(IN OUT PIRP Irp, PURB Urb);
|
||||||
|
NTSTATUS HandleGetDescriptorFromInterface(IN OUT PIRP Irp, PURB Urb);
|
||||||
NTSTATUS HandleClassDevice(IN OUT PIRP Irp, PURB Urb);
|
NTSTATUS HandleClassDevice(IN OUT PIRP Irp, PURB Urb);
|
||||||
NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb);
|
NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb);
|
||||||
NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb);
|
NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb);
|
||||||
|
@ -1223,6 +1224,55 @@ CHubController::HandleClassDevice(
|
||||||
|
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
NTSTATUS
|
||||||
|
CHubController::HandleGetDescriptorFromInterface(
|
||||||
|
IN OUT PIRP Irp,
|
||||||
|
IN OUT PURB Urb)
|
||||||
|
{
|
||||||
|
PUSBDEVICE UsbDevice;
|
||||||
|
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
ASSERT(Urb->UrbControlDescriptorRequest.TransferBufferLength);
|
||||||
|
ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
|
||||||
|
|
||||||
|
//
|
||||||
|
// check if this is a valid usb device handle
|
||||||
|
//
|
||||||
|
ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)));
|
||||||
|
|
||||||
|
//
|
||||||
|
// get device
|
||||||
|
//
|
||||||
|
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
|
||||||
|
|
||||||
|
//
|
||||||
|
// generate setup packet
|
||||||
|
//
|
||||||
|
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
|
||||||
|
CtrlSetup.wValue.LowByte = Urb->UrbControlDescriptorRequest.Index;
|
||||||
|
CtrlSetup.wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType;
|
||||||
|
CtrlSetup.wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId;
|
||||||
|
CtrlSetup.wLength = (USHORT)Urb->UrbControlDescriptorRequest.TransferBufferLength;
|
||||||
|
CtrlSetup.bmRequestType.B = 0x81;
|
||||||
|
|
||||||
|
//
|
||||||
|
// submit setup packet
|
||||||
|
//
|
||||||
|
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
|
||||||
|
ASSERT(Status == STATUS_SUCCESS);
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CHubController::HandleGetDescriptor(
|
CHubController::HandleGetDescriptor(
|
||||||
|
@ -1492,8 +1542,8 @@ CHubController::HandleClassInterface(
|
||||||
//
|
//
|
||||||
// sanity check
|
// sanity check
|
||||||
//
|
//
|
||||||
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
|
//ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer || Urb->UrbControlVendorClassRequest.TransferBufferMDL);
|
||||||
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength);
|
//ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength);
|
||||||
PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
|
PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1520,7 +1570,7 @@ CHubController::HandleClassInterface(
|
||||||
//
|
//
|
||||||
// initialize setup packet
|
// initialize setup packet
|
||||||
//
|
//
|
||||||
CtrlSetup.bmRequestType.B = 0xa1; //FIXME: Const.
|
CtrlSetup.bmRequestType.B = 0xa1;
|
||||||
CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
|
CtrlSetup.bRequest = Urb->UrbControlVendorClassRequest.Request;
|
||||||
CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
|
CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
|
||||||
CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
|
CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
|
||||||
|
@ -1579,6 +1629,9 @@ CHubController::HandleDeviceControl(
|
||||||
|
|
||||||
switch (Urb->UrbHeader.Function)
|
switch (Urb->UrbHeader.Function)
|
||||||
{
|
{
|
||||||
|
case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE:
|
||||||
|
Status = HandleGetDescriptorFromInterface(Irp, Urb);
|
||||||
|
break;
|
||||||
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
|
||||||
Status = HandleGetDescriptor(Irp, Urb);
|
Status = HandleGetDescriptor(Irp, Urb);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -188,6 +188,14 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
|
||||||
|
|
||||||
virtual NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0;
|
virtual NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetInterruptEndpointDescriptors
|
||||||
|
//
|
||||||
|
// Description: returns interrupt endpoint descriptors
|
||||||
|
|
||||||
|
virtual NTSTATUS GetInterruptEndpointDescriptors(struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptorArray) = 0;
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// HeadEndpointDescriptorModified
|
// HeadEndpointDescriptorModified
|
||||||
|
@ -451,6 +459,15 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
|
||||||
// Description: frees the associated endpoint descriptor and its general descriptors
|
// Description: frees the associated endpoint descriptor and its general descriptors
|
||||||
|
|
||||||
virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor) = 0;
|
virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor) = 0;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// GetInterruptInterval
|
||||||
|
//
|
||||||
|
// Description: returns interval of the iso / interrupt
|
||||||
|
|
||||||
|
virtual UCHAR GetInterval() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,12 @@ public:
|
||||||
// local functions
|
// local functions
|
||||||
BOOLEAN IsTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
|
BOOLEAN IsTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress);
|
||||||
NTSTATUS FindTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
|
NTSTATUS FindTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
|
||||||
|
NTSTATUS FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor);
|
||||||
|
|
||||||
VOID CleanupEndpointDescriptor(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor);
|
VOID CleanupEndpointDescriptor(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor);
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR FindInterruptEndpointDescriptor(UCHAR InterruptInterval);
|
||||||
|
VOID PrintEndpointList(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
|
||||||
|
VOID LinkEndpoint(POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor);
|
||||||
|
|
||||||
// constructor / destructor
|
// constructor / destructor
|
||||||
CUSBQueue(IUnknown *OuterUnknown){}
|
CUSBQueue(IUnknown *OuterUnknown){}
|
||||||
|
@ -56,6 +61,7 @@ protected:
|
||||||
PUSBHARDWAREDEVICE m_Hardware; // hardware
|
PUSBHARDWAREDEVICE m_Hardware; // hardware
|
||||||
POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor
|
POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor
|
||||||
POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor
|
POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints;
|
||||||
};
|
};
|
||||||
|
|
||||||
//=================================================================================================
|
//=================================================================================================
|
||||||
|
@ -94,6 +100,11 @@ CUSBQueue::Initialize(
|
||||||
//
|
//
|
||||||
Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor);
|
Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get interrupt endpoints
|
||||||
|
//
|
||||||
|
Hardware->GetInterruptEndpointDescriptors(&m_InterruptEndpoints);
|
||||||
|
|
||||||
//
|
//
|
||||||
// initialize spinlock
|
// initialize spinlock
|
||||||
//
|
//
|
||||||
|
@ -118,6 +129,32 @@ CUSBQueue::GetPendingRequestCount()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
CUSBQueue::LinkEndpoint(
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR HeadEndpointDescriptor,
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
|
||||||
|
{
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor = HeadEndpointDescriptor;
|
||||||
|
|
||||||
|
//
|
||||||
|
// get last descriptor in queue
|
||||||
|
//
|
||||||
|
while(CurrentEndpointDescriptor->NextDescriptor)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// move to last descriptor
|
||||||
|
//
|
||||||
|
CurrentEndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentEndpointDescriptor->NextDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// link endpoints
|
||||||
|
//
|
||||||
|
CurrentEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->PhysicalAddress.LowPart;
|
||||||
|
CurrentEndpointDescriptor->NextDescriptor = EndpointDescriptor;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CUSBQueue::AddUSBRequest(
|
CUSBQueue::AddUSBRequest(
|
||||||
IUSBRequest * Request)
|
IUSBRequest * Request)
|
||||||
|
@ -146,10 +183,10 @@ CUSBQueue::AddUSBRequest(
|
||||||
switch(Type)
|
switch(Type)
|
||||||
{
|
{
|
||||||
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
|
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
|
||||||
case USB_ENDPOINT_TYPE_INTERRUPT:
|
|
||||||
/* NOT IMPLEMENTED IN QUEUE */
|
/* NOT IMPLEMENTED IN QUEUE */
|
||||||
Status = STATUS_NOT_SUPPORTED;
|
Status = STATUS_NOT_SUPPORTED;
|
||||||
break;
|
break;
|
||||||
|
case USB_ENDPOINT_TYPE_INTERRUPT:
|
||||||
case USB_ENDPOINT_TYPE_CONTROL:
|
case USB_ENDPOINT_TYPE_CONTROL:
|
||||||
case USB_ENDPOINT_TYPE_BULK:
|
case USB_ENDPOINT_TYPE_BULK:
|
||||||
Status = STATUS_SUCCESS;
|
Status = STATUS_SUCCESS;
|
||||||
|
@ -213,31 +250,35 @@ CUSBQueue::AddUSBRequest(
|
||||||
//
|
//
|
||||||
HeadDescriptor = m_ControlHeadEndpointDescriptor;
|
HeadDescriptor = m_ControlHeadEndpointDescriptor;
|
||||||
}
|
}
|
||||||
|
else if (Type == USB_ENDPOINT_TYPE_INTERRUPT)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// get head descriptor
|
||||||
|
//
|
||||||
|
HeadDescriptor = FindInterruptEndpointDescriptor(Request->GetInterval());
|
||||||
|
ASSERT(HeadDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// link endpoints
|
// insert endpoint at end
|
||||||
//
|
//
|
||||||
Descriptor->NextPhysicalEndpoint = HeadDescriptor->NextPhysicalEndpoint;
|
LinkEndpoint(HeadDescriptor, Descriptor);
|
||||||
Descriptor->NextDescriptor = HeadDescriptor->NextDescriptor;
|
|
||||||
|
|
||||||
HeadDescriptor->NextPhysicalEndpoint = Descriptor->PhysicalAddress.LowPart;
|
|
||||||
HeadDescriptor->NextDescriptor = Descriptor;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// set descriptor active
|
// set descriptor active
|
||||||
//
|
//
|
||||||
Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
|
Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
|
||||||
//HeadDescriptor->Flags &= ~OHCI_ENDPOINT_SKIP;
|
|
||||||
|
|
||||||
DPRINT("Request %x Logical %x added to queue Queue %p Logical %x\n", Descriptor, Descriptor->PhysicalAddress.LowPart, HeadDescriptor, HeadDescriptor->PhysicalAddress.LowPart);
|
DPRINT("Request %x Logical %x added to queue Queue %p Logical %x\n", Descriptor, Descriptor->PhysicalAddress.LowPart, HeadDescriptor, HeadDescriptor->PhysicalAddress.LowPart);
|
||||||
|
|
||||||
|
|
||||||
//
|
if (Type == USB_ENDPOINT_TYPE_CONTROL || Type == USB_ENDPOINT_TYPE_BULK)
|
||||||
// notify hardware of our request
|
{
|
||||||
//
|
//
|
||||||
m_Hardware->HeadEndpointDescriptorModified(Type);
|
// notify hardware of our request
|
||||||
|
//
|
||||||
|
m_Hardware->HeadEndpointDescriptorModified(Type);
|
||||||
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -318,6 +359,35 @@ CUSBQueue::FindTransferDescriptorInEndpoint(
|
||||||
return STATUS_NOT_FOUND;
|
return STATUS_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
CUSBQueue::FindTransferDescriptorInInterruptHeadEndpoints(IN ULONG TransferDescriptorLogicalAddress, OUT POHCI_ENDPOINT_DESCRIPTOR *OutEndpointDescriptor, OUT POHCI_ENDPOINT_DESCRIPTOR *OutPreviousEndpointDescriptor)
|
||||||
|
{
|
||||||
|
ULONG Index;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// search descriptor in endpoint list
|
||||||
|
//
|
||||||
|
for(Index = 0; Index < OHCI_STATIC_ENDPOINT_COUNT; Index++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// is it in current endpoint
|
||||||
|
//
|
||||||
|
Status = FindTransferDescriptorInEndpoint(m_InterruptEndpoints[Index], TransferDescriptorLogicalAddress, OutEndpointDescriptor, OutPreviousEndpointDescriptor);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// found transfer descriptor
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// not found
|
||||||
|
//
|
||||||
|
return STATUS_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
CUSBQueue::IsTransferDescriptorInEndpoint(
|
CUSBQueue::IsTransferDescriptorInEndpoint(
|
||||||
|
@ -399,7 +469,27 @@ CUSBQueue::CleanupEndpointDescriptor(
|
||||||
Request->Release();
|
Request->Release();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
VOID
|
||||||
|
CUSBQueue::PrintEndpointList(
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor)
|
||||||
|
{
|
||||||
|
DPRINT1("CUSBQueue::PrintEndpointList HeadEndpoint %p Logical %x\n", EndpointDescriptor, EndpointDescriptor->PhysicalAddress.LowPart);
|
||||||
|
|
||||||
|
//
|
||||||
|
// get first general transfer descriptor
|
||||||
|
//
|
||||||
|
EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
|
||||||
|
|
||||||
|
while(EndpointDescriptor)
|
||||||
|
{
|
||||||
|
DPRINT1(" CUSBQueue::PrintEndpointList Endpoint %p Logical %x\n", EndpointDescriptor, EndpointDescriptor->PhysicalAddress.LowPart);
|
||||||
|
|
||||||
|
//
|
||||||
|
// move to next
|
||||||
|
//
|
||||||
|
EndpointDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)EndpointDescriptor->NextDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
CUSBQueue::TransferDescriptorCompletionCallback(
|
CUSBQueue::TransferDescriptorCompletionCallback(
|
||||||
|
@ -444,14 +534,73 @@ CUSBQueue::TransferDescriptorCompletionCallback(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// find transfer descriptor in interrupt list
|
||||||
|
//
|
||||||
|
Status = FindTransferDescriptorInInterruptHeadEndpoints(TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// cleanup endpoint
|
||||||
|
//
|
||||||
|
CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
|
||||||
|
|
||||||
|
//
|
||||||
|
// done
|
||||||
|
//
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// hardware reported dead endpoint completed
|
// hardware reported dead endpoint completed
|
||||||
//
|
//
|
||||||
DPRINT1("CUSBQueue::TransferDescriptorCompletionCallback invalid transfer descriptor %x\n", TransferDescriptorLogicalAddress);
|
DPRINT("CUSBQueue::TransferDescriptorCompletionCallback invalid transfer descriptor %x\n", TransferDescriptorLogicalAddress);
|
||||||
ASSERT(FALSE);
|
ASSERT(FALSE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
POHCI_ENDPOINT_DESCRIPTOR
|
||||||
|
CUSBQueue::FindInterruptEndpointDescriptor(
|
||||||
|
UCHAR InterruptInterval)
|
||||||
|
{
|
||||||
|
ULONG Index = 0;
|
||||||
|
ULONG Power = 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
// sanity check
|
||||||
|
//
|
||||||
|
ASSERT(InterruptInterval < OHCI_BIGGEST_INTERVAL);
|
||||||
|
|
||||||
|
//
|
||||||
|
// find interrupt index
|
||||||
|
//
|
||||||
|
while (Power <= OHCI_BIGGEST_INTERVAL / 2)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// is current interval greater
|
||||||
|
//
|
||||||
|
if (Power * 2 > InterruptInterval)
|
||||||
|
break;
|
||||||
|
|
||||||
|
//
|
||||||
|
// increment power
|
||||||
|
//
|
||||||
|
Power *= 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// move to next interrupt
|
||||||
|
//
|
||||||
|
Index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT("InterruptInterval %lu Selected InterruptIndex %lu Choosen Interval %lu\n", InterruptInterval, Index, Power);
|
||||||
|
|
||||||
|
//
|
||||||
|
// return endpoint
|
||||||
|
//
|
||||||
|
return m_InterruptEndpoints[Index];
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
CreateUSBQueue(
|
CreateUSBQueue(
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
|
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
|
||||||
virtual VOID CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
|
virtual VOID CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
|
||||||
virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
|
virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
|
||||||
|
virtual UCHAR GetInterval();
|
||||||
|
|
||||||
|
|
||||||
// local functions
|
// local functions
|
||||||
ULONG InternalGetTransferType();
|
ULONG InternalGetTransferType();
|
||||||
|
@ -377,6 +379,18 @@ CUSBRequest::GetMaxPacketSize()
|
||||||
return m_EndpointDescriptor->wMaxPacketSize;
|
return m_EndpointDescriptor->wMaxPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UCHAR
|
||||||
|
CUSBRequest::GetInterval()
|
||||||
|
{
|
||||||
|
ASSERT(m_EndpointDescriptor);
|
||||||
|
ASSERT((m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
|
||||||
|
|
||||||
|
//
|
||||||
|
// return interrupt interval
|
||||||
|
//
|
||||||
|
return m_EndpointDescriptor->bInterval;
|
||||||
|
}
|
||||||
|
|
||||||
UCHAR
|
UCHAR
|
||||||
CUSBRequest::GetEndpointAddress()
|
CUSBRequest::GetEndpointAddress()
|
||||||
{
|
{
|
||||||
|
@ -786,7 +800,7 @@ CUSBRequest::BuildBulkInterruptEndpoint(
|
||||||
FirstDescriptor = CurrentDescriptor;
|
FirstDescriptor = CurrentDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("PreviousDescriptor %p CurrentDescriptor %p Buffer Logical %p Physical %x Last Physical %x CurrentSize %lu\n", PreviousDescriptor, CurrentDescriptor, CurrentDescriptor->BufferLogical, CurrentDescriptor->BufferPhysical, CurrentDescriptor->LastPhysicalByteAddress, CurrentSize);
|
DPRINT("PreviousDescriptor %p CurrentDescriptor %p Logical %x Buffer Logical %p Physical %x Last Physical %x CurrentSize %lu\n", PreviousDescriptor, CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, CurrentDescriptor->BufferLogical, CurrentDescriptor->BufferPhysical, CurrentDescriptor->LastPhysicalByteAddress, CurrentSize);
|
||||||
|
|
||||||
//
|
//
|
||||||
// set previous descriptor
|
// set previous descriptor
|
||||||
|
@ -847,7 +861,6 @@ CUSBRequest::BuildBulkInterruptEndpoint(
|
||||||
// done
|
// done
|
||||||
//
|
//
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue