[USBEHCI_NEW]

- Null terminate buffer from IOCTL_USB_GET_ROOT_HUB_NAME, fixes usbview problems
- Implement URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER, IUSBHardware needs more work
- Silence debug traces
- Start implementing IUSBRequest interfaces
- Complete unhandled major irp with status success

svn path=/branches/usb-bringup/; revision=51396
This commit is contained in:
Johannes Anderwald 2011-04-19 01:21:10 +00:00
parent d3e13a4ada
commit 3ac2c07f55
7 changed files with 1083 additions and 55 deletions

View file

@ -7,6 +7,7 @@ add_definitions(-D_WIN32_WINNT=0x600)
add_library(usbehci SHARED add_library(usbehci SHARED
usbehci.cpp usbehci.cpp
usb_device.cpp usb_device.cpp
usb_request.cpp
usb_queue.cpp usb_queue.cpp
hcd_controller.cpp hcd_controller.cpp
hardware.cpp hardware.cpp

View file

@ -327,8 +327,11 @@ CHCDController::HandleDeviceControl(
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
// //
// informal debug print // null terminate it
// //
PC_ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG) - sizeof(WCHAR) >= ResultLength);
DriverKey->DriverKeyName[ResultLength / sizeof(WCHAR)] = L'\0';
DPRINT1("Result %S\n", DriverKey->DriverKeyName); DPRINT1("Result %S\n", DriverKey->DriverKeyName);
} }
@ -552,7 +555,6 @@ CHCDController::HandlePnp(
} }
default: default:
{ {
DPRINT1("CHCDController::HandlePnp Dispatch to lower device object %lx\n", IoStack->MinorFunction);
// //
// forward irp to next device object // forward irp to next device object
// //

View file

@ -61,6 +61,8 @@ public:
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);
NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb);
NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb);
// constructor / destructor // constructor / destructor
CHubController(IUnknown *OuterUnknown){} CHubController(IUnknown *OuterUnknown){}
@ -155,6 +157,20 @@ const UCHAR ROOTHUB2_ENDPOINT_DESCRIPTOR [] =
0xFF /* bInterval; (255ms -- usb 2.0 spec) */ 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 NTSTATUS
STDMETHODCALLTYPE STDMETHODCALLTYPE
@ -653,7 +669,9 @@ CHubController::HandlePnp(
} }
default: default:
{ {
DPRINT1("CHubController::HandlePnp Unhandeled %x\n", IoStack->MinorFunction); //
// ignore request with default status
//
Status = Irp->IoStatus.Status; Status = Irp->IoStatus.Status;
break; break;
} }
@ -682,6 +700,15 @@ CHubController::HandlePower(
IoCompleteRequest(Irp, IO_NO_INCREMENT); IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
} }
//-----------------------------------------------------------------------------------------
NTSTATUS
CHubController::HandleBulkOrInterruptTransfer(
IN OUT PIRP Irp,
PURB Urb)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------
NTSTATUS NTSTATUS
@ -689,11 +716,143 @@ CHubController::HandleClassOther(
IN OUT PIRP Irp, IN OUT PIRP Irp,
PURB Urb) PURB Urb)
{ {
DPRINT1("CHubController::HandleClassOther> Request %x Value %x not implemented\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value); NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
USHORT PortStatus = 0, PortChange = 0;
PUSHORT Buffer;
ULONG NumPort;
ULONG PortId;
//DPRINT1("CHubController::HandleClassOther> Request %x Value %x not implemented\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value);
// //
// FIXME implement me // get number of ports available
// //
Status = m_Hardware->GetDeviceDetails(NULL, NULL, &NumPort, NULL);
PC_ASSERT(Status == STATUS_SUCCESS);
//
// sanity check
//
PC_ASSERT(Urb->UrbControlVendorClassRequest.Index - 1 < NumPort);
//
// port range reported start from 1 -n
// convert back port id so it matches the hardware
//
PortId = Urb->UrbControlVendorClassRequest.Index - 1;
//
// check request code
//
switch(Urb->UrbControlVendorClassRequest.Request)
{
case USB_REQUEST_GET_STATUS:
{
//
// sanity check
//
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBufferLength == sizeof(USHORT) * 2);
PC_ASSERT(Urb->UrbControlVendorClassRequest.TransferBuffer);
//
// get port status
//
//Status = m_Hardware->GetPortStatus(PortId, &PortStatus, &PortChange);
Status = STATUS_SUCCESS;
if (NT_SUCCESS(Status))
{
//
// request contains buffer of 2 ushort which are used from submitting port status and port change status
//
Buffer = (PUSHORT)Urb->UrbControlVendorClassRequest.TransferBuffer;
//
// store status, then port change
//
*Buffer = PortStatus;
Buffer++;
*Buffer = PortChange;
}
//
// done
//
break;
}
case USB_REQUEST_CLEAR_FEATURE:
{
switch (Urb->UrbControlVendorClassRequest.Value)
{
case C_PORT_CONNECTION:
//Status = m_Hardware->ClearPortStatus(PortId, C_PORT_CONNECTION);
break;
case C_PORT_RESET:
//Status= m_Hardware->ClearPortStatus(PortId, C_PORT_RESET);
break;
default:
DPRINT("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
PC_ASSERT(FALSE);
break;
}
Status = STATUS_SUCCESS;
break;
}
case USB_REQUEST_SET_FEATURE:
{
//
// request set feature
//
switch(Urb->UrbControlVendorClassRequest.Value)
{
case PORT_ENABLE:
{
//
// port enable is a no-op for EHCI
//
Status = STATUS_SUCCESS;
break;
}
case PORT_SUSPEND:
{
//
// set suspend port feature
//
Status = STATUS_SUCCESS; //m_Hardware->SetPortFeature(PortId, PORT_SUSPEND);
break;
}
case PORT_POWER:
{
//
// set power feature on port
//
Status = STATUS_SUCCESS; //m_Hardware->SetPortFeature(PortId, PORT_POWER);
break;
}
case PORT_RESET:
{
//
// reset port feature
//
Status = m_Hardware->ResetPort(PortId);
PC_ASSERT(Status == STATUS_SUCCESS);
break;
}
default:
DPRINT1("Unsupported request id %x\n", Urb->UrbControlVendorClassRequest.Value);
PC_ASSERT(FALSE);
}
break;
}
default:
DPRINT1("CHubController::HandleClassOther Unknown request code %x\n", Urb->UrbControlVendorClassRequest.Request);
PC_ASSERT(0);
Status = STATUS_INVALID_DEVICE_REQUEST;
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -862,7 +1021,6 @@ CHubController::HandleGetDescriptor(
if (Urb->UrbHeader.UsbdDeviceHandle == NULL) if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
{ {
DPRINT1("Root Hub descriptor\n");
// //
// copy root hub device descriptor // copy root hub device descriptor
// //
@ -960,13 +1118,6 @@ CHubController::HandleDeviceControl(
// //
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension; DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
DPRINT1("HandleDeviceControl>Type: FDO %u IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n",
DeviceExtension->IsFDO,
IoStack->Parameters.DeviceIoControl.IoControlCode,
IoStack->Parameters.DeviceIoControl.InputBufferLength,
IoStack->Parameters.DeviceIoControl.OutputBufferLength);
// //
// determine which request should be performed // determine which request should be performed
// //
@ -980,8 +1131,6 @@ CHubController::HandleDeviceControl(
Urb = (PURB)IoStack->Parameters.Others.Argument1; Urb = (PURB)IoStack->Parameters.Others.Argument1;
PC_ASSERT(Urb); PC_ASSERT(Urb);
DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x Length %lu Status %x Handle %p Flags %x UNIMPLEMENTED\n", Urb->UrbHeader.Function, Urb->UrbHeader.Length, Urb->UrbHeader.Status, Urb->UrbHeader.UsbdDeviceHandle, Urb->UrbHeader.UsbdFlags);
switch (Urb->UrbHeader.Function) switch (Urb->UrbHeader.Function)
{ {
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
@ -999,6 +1148,12 @@ CHubController::HandleDeviceControl(
case URB_FUNCTION_CLASS_OTHER: case URB_FUNCTION_CLASS_OTHER:
Status = HandleClassOther(Irp, Urb); Status = HandleClassOther(Irp, Urb);
break; break;
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
Status = HandleBulkOrInterruptTransfer(Irp, Urb);
break;
default:
DPRINT1("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x NOT IMPLEMENTED\n", Urb->UrbHeader.Function);
break;
} }
// //
// request completed // request completed
@ -1007,7 +1162,7 @@ CHubController::HandleDeviceControl(
} }
case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE: case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
{ {
DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n"); DPRINT("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
if (IoStack->Parameters.Others.Argument1) if (IoStack->Parameters.Others.Argument1)
{ {
@ -1032,7 +1187,7 @@ CHubController::HandleDeviceControl(
} }
case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO: case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
{ {
DPRINT1("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n"); DPRINT("IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO\n");
// //
// this is the first request send, it delivers the PDO to the caller // this is the first request send, it delivers the PDO to the caller
@ -1061,7 +1216,7 @@ CHubController::HandleDeviceControl(
} }
case IOCTL_INTERNAL_USB_GET_HUB_COUNT: case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
{ {
DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n"); DPRINT("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n");
// //
// after IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO is delivered, the usbhub driver // after IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO is delivered, the usbhub driver
@ -1082,6 +1237,14 @@ CHubController::HandleDeviceControl(
Irp->IoStatus.Information = sizeof(ULONG); Irp->IoStatus.Information = sizeof(ULONG);
break; break;
} }
default:
{
DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu NOT IMPLEMENTED\n",
IoStack->Parameters.DeviceIoControl.IoControlCode,
IoStack->Parameters.DeviceIoControl.InputBufferLength,
IoStack->Parameters.DeviceIoControl.OutputBufferLength);
break;
}
} }
Irp->IoStatus.Status = Status; Irp->IoStatus.Status = Status;
@ -1921,7 +2084,37 @@ USBHI_GetControllerInformation(
ULONG ControllerInformationBufferLength, ULONG ControllerInformationBufferLength,
PULONG LengthReturned) PULONG LengthReturned)
{ {
UNIMPLEMENTED PUSB_CONTROLLER_INFORMATION_0 ControllerInfo;
DPRINT1("USBHI_GetControllerInformation\n");
//
// sanity checks
//
PC_ASSERT(ControllerInformationBuffer);
PC_ASSERT(ControllerInformationBufferLength >= sizeof(USB_CONTROLLER_INFORMATION_0));
//
// get controller info buffer
//
ControllerInfo = (PUSB_CONTROLLER_INFORMATION_0)ControllerInformationBuffer;
//
// FIXME only version 0 is supported for now
//
PC_ASSERT(ControllerInfo->InformationLevel == 0);
//
// fill in information
//
ControllerInfo->ActualLength = sizeof(USB_CONTROLLER_INFORMATION_0);
ControllerInfo->SelectiveSuspendEnabled = FALSE; //FIXME
ControllerInfo->IsHighSpeedController = TRUE;
//
// set length returned
//
*LengthReturned = ControllerInfo->ActualLength;
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
} }

View file

@ -312,6 +312,8 @@ typedef IDMAMemoryManager *PDMAMEMORYMANAGER;
// CancelCallback routine is invoked. // CancelCallback routine is invoked.
// //
struct _QUEUE_HEAD;
DECLARE_INTERFACE_(IUSBRequest, IUnknown) DECLARE_INTERFACE_(IUSBRequest, IUnknown)
{ {
DEFINE_ABSTRACT_UNKNOWN() DEFINE_ABSTRACT_UNKNOWN()
@ -324,44 +326,39 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
// If there is a TransferBuffer, the TransferBufferLength contains the length of the buffer // If there is a TransferBuffer, the TransferBufferLength contains the length of the buffer
virtual NTSTATUS InitializeWithSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager,
IN ULONG TransferBufferLength, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
IN PVOID TransferBuffer) = 0; IN OUT ULONG TransferBufferLength,
IN OUT PMDL TransferBuffer) = 0;
//
//TODO: find required parameters for different packet types
//
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------
// //
// SetEndPoint // InitializeWithIrp
// //
// Description: sets the endpoint of the request. // Description: initializes the request with an IRP
// The irp contains an URB block which contains all necessary information
virtual NTSTATUS SetEndPoint(PUSB_ENDPOINT_DESCRIPTOR EndPoint); virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager,
IN OUT PIRP Irp);
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------
// //
// SetCompletionDetails // SetCompletionEvent
// //
// Description: sets up how the request should be completed // Description: sets up completion event which is signaled when the
// If an irp is passed, then it is completed with status code of the // request is completed or cancelled
// CompletionCallback or CancelCallback
// If an event is passed, then the event is signaled
virtual NTSTATUS SetCompletionDetails(IN OPTIONAL PIRP Irp, virtual NTSTATUS SetCompletionEvent(IN PKEVENT Event) = 0;
IN OPTIONAL PKEVENT Event) = 0;
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------
// //
// CompletionCallback // CompletionCallback
// //
// Description: called when request has been completed. It is called when // Description: called when request has been completed. It is called when
// IUSBQueue completes the request // IUSBQueue completes the request
virtual VOID CompletionCallback(IN NTSTATUS NtStatusCode, virtual VOID CompletionCallback(IN NTSTATUS NtStatusCode,
IN ULONG UrbStatusCode) = 0; IN ULONG UrbStatusCode) = 0;
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------
// //
@ -371,6 +368,31 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
virtual VOID CancelCallback(IN NTSTATUS NtStatusCode) = 0; virtual VOID CancelCallback(IN NTSTATUS NtStatusCode) = 0;
//-----------------------------------------------------------------------------------------
//
// GetQueueHead
//
// Description: returns an initialized queue head with contains the all transfer descriptors
virtual NTSTATUS GetQueueHead(struct _QUEUE_HEAD ** OutHead) = 0;
//-----------------------------------------------------------------------------------------
//
// IsRequestComplete
//
// Description: returns true when the request has been completed
// Should be called after the CompletionCallback has been invoked
virtual BOOLEAN IsRequestComplete() = 0;
//-----------------------------------------------------------------------------------------
//
// GetTransferType
//
// Description: returns the type of the request: control, bulk, iso, interrupt
virtual ULONG GetTransferType() = 0;
}; };
typedef IUSBRequest *PUSBREQUEST; typedef IUSBRequest *PUSBREQUEST;

View file

@ -68,6 +68,7 @@ protected:
USB_DEVICE_DESCRIPTOR m_DeviceDescriptor; USB_DEVICE_DESCRIPTOR m_DeviceDescriptor;
ULONG m_PortStatus; ULONG m_PortStatus;
PUSBQUEUE m_Queue; PUSBQUEUE m_Queue;
PDMAMEMORYMANAGER m_DmaManager;
}; };
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
@ -124,6 +125,21 @@ CUSBDevice::Initialize(
return Status; return Status;
} }
//
// FIXME: get dma manager
//
//Status = m_Device->GetDMA(&m_DmaManager);
if (!NT_SUCCESS(Status))
{
//
// failed to get usb queue
//
DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status);
return Status;
}
// //
// zero descriptor // zero descriptor
// //
@ -293,7 +309,7 @@ CUSBDevice::SetDeviceAddress(
// initialize request // initialize request
// //
CtrlSetup.bRequest = USB_REQUEST_SET_ADDRESS; CtrlSetup.bRequest = USB_REQUEST_SET_ADDRESS;
CtrlSetup.wValue.W = DeviceAddress; CtrlSetup.wValue.W = (USHORT)DeviceAddress;
// //
// set device address // set device address
@ -386,6 +402,8 @@ CUSBDevice::CommitSetupPacket(
PUSBREQUEST Request; PUSBREQUEST Request;
KEVENT Event; KEVENT Event;
BOOLEAN Wait = FALSE; BOOLEAN Wait = FALSE;
PMDL Mdl = 0;
if (!m_Queue) if (!m_Queue)
{ {
@ -409,10 +427,12 @@ CUSBDevice::CommitSetupPacket(
return Status; return Status;
} }
/* FIXME build MDL */
// //
// initialize request // initialize request
// //
Status = Request->InitializeWithSetupPacket(Packet, BufferLength, Buffer); Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, BufferLength, Mdl);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
// //
@ -439,7 +459,7 @@ CUSBDevice::CommitSetupPacket(
// //
// set completion details // set completion details
// //
Status = Request->SetCompletionDetails(Irp, pEvent); Status = Request->SetCompletionEvent(pEvent);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
// //

View file

@ -0,0 +1,801 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbehci/usb_request.cpp
* PURPOSE: USB EHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#define INITGUID
#include "usbehci.h"
#include "hardware.h"
class CUSBRequest : public IUSBRequest
{
public:
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
{
InterlockedIncrement(&m_Ref);
return m_Ref;
}
STDMETHODIMP_(ULONG) Release()
{
InterlockedDecrement(&m_Ref);
if (!m_Ref)
{
delete this;
return 0;
}
return m_Ref;
}
// IUSBRequest interface functions
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp);
virtual NTSTATUS SetCompletionEvent(IN PKEVENT Event);
virtual VOID CompletionCallback(IN NTSTATUS NtStatusCode, IN ULONG UrbStatusCode);
virtual VOID CancelCallback(IN NTSTATUS NtStatusCode);
virtual NTSTATUS GetQueueHead(struct _QUEUE_HEAD ** OutHead);
virtual BOOLEAN IsRequestComplete();
virtual ULONG GetTransferType();
// local functions
ULONG InternalGetTransferType();
NTSTATUS BuildControlTransferQueueHead(PQUEUE_HEAD * OutHead);
NTSTATUS BuildBulkTransferQueueHead(PQUEUE_HEAD * OutHead);
NTSTATUS CreateDescriptor(PQUEUE_TRANSFER_DESCRIPTOR *OutDescriptor);
NTSTATUS CreateQueueHead(PQUEUE_HEAD *OutQueueHead);
ULONG GetDeviceAddress();
NTSTATUS BuildSetupPacket();
// constructor / destructor
CUSBRequest(IUnknown *OuterUnknown){}
virtual ~CUSBRequest(){}
protected:
LONG m_Ref;
PDMAMEMORYMANAGER m_DmaManager;
PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
ULONG m_TransferBufferLength;
PMDL m_TransferBufferMDL;
PIRP m_Irp;
PKEVENT m_CompletionEvent;
PQUEUE_HEAD m_QueueHead;
PQUEUE_TRANSFER_DESCRIPTOR m_TransferDescriptors[3];
PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
};
//----------------------------------------------------------------------------------------
NTSTATUS
STDMETHODCALLTYPE
CUSBRequest::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
return STATUS_UNSUCCESSFUL;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::InitializeWithSetupPacket(
IN PDMAMEMORYMANAGER DmaManager,
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
IN OUT ULONG TransferBufferLength,
IN OUT PMDL TransferBuffer)
{
//
// sanity checks
//
PC_ASSERT(DmaManager);
PC_ASSERT(SetupPacket);
//
// initialize packet
//
m_DmaManager = DmaManager;
m_SetupPacket = SetupPacket;
m_TransferBufferLength = TransferBufferLength;
m_TransferBufferMDL = TransferBuffer;
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::InitializeWithIrp(
IN PDMAMEMORYMANAGER DmaManager,
IN OUT PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
NTSTATUS Status;
//
// sanity checks
//
PC_ASSERT(DmaManager);
PC_ASSERT(Irp);
//
// get current irp stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
//
// sanity check
//
PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
//
// get urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// store irp
//
m_Irp = Irp;
//
// check function type
//
switch (Urb->UrbHeader.Function)
{
//
// luckily those request have the same structure layout
//
case URB_FUNCTION_CLASS_INTERFACE:
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
{
//
// bulk / interrupt transfer
//
if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
{
//
// it must have an MDL
//
PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
//
// get mdl buffer
//
m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
}
break;
}
default:
DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
PC_ASSERT(FALSE);
}
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::SetCompletionEvent(
IN PKEVENT Event)
{
if (m_QueueHead)
{
//
// WTF? operation is already in progress
//
return STATUS_UNSUCCESSFUL;
}
//
// store completion event
//
m_CompletionEvent = Event;
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
VOID
CUSBRequest::CompletionCallback(
IN NTSTATUS NtStatusCode,
IN ULONG UrbStatusCode)
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
if (m_Irp)
{
//
// set irp completion status
//
m_Irp->IoStatus.Status = NtStatusCode;
//
// get current irp stack location
//
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
//
// get urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// store urb status
//
Urb->UrbHeader.Status = UrbStatusCode;
//
// check if the request was successfull
//
if (!NT_SUCCESS(NtStatusCode))
{
//
// set returned length to zero in case of error
//
Urb->UrbHeader.Length = 0;
}
//
// FIXME: check if the transfer was split
// if yes dont complete irp yet
//
IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
}
if (m_CompletionEvent)
{
//
// FIXME: make sure the request was not split
//
KeSetEvent(m_CompletionEvent, 0, FALSE);
}
}
//----------------------------------------------------------------------------------------
VOID
CUSBRequest::CancelCallback(
IN NTSTATUS NtStatusCode)
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
if (m_Irp)
{
//
// set irp completion status
//
m_Irp->IoStatus.Status = NtStatusCode;
//
// get current irp stack location
//
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
//
// get urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// store urb status
//
Urb->UrbHeader.Status = USBD_STATUS_CANCELED;
Urb->UrbHeader.Length = 0;
//
// FIXME: check if the transfer was split
// if yes dont complete irp yet
//
IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
}
if (m_CompletionEvent)
{
//
// FIXME: make sure the request was not split
//
KeSetEvent(m_CompletionEvent, 0, FALSE);
}
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::GetQueueHead(
struct _QUEUE_HEAD ** OutHead)
{
ULONG TransferType;
NTSTATUS Status;
//
// first get transfer type
//
TransferType = InternalGetTransferType();
//
// build request depending on type
//
switch(TransferType)
{
case USB_ENDPOINT_TYPE_CONTROL:
Status = BuildControlTransferQueueHead(OutHead);
break;
case USB_ENDPOINT_TYPE_BULK:
Status = BuildBulkTransferQueueHead(OutHead);
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
DPRINT1("USB_ENDPOINT_TYPE_INTERRUPT not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
if (NT_SUCCESS(Status))
{
//
// store queue head
//
m_QueueHead = *OutHead;
}
//
// done
//
return Status;
}
//----------------------------------------------------------------------------------------
BOOLEAN
CUSBRequest::IsRequestComplete()
{
//
// FIXME: check if request was split
//
return TRUE;
}
//----------------------------------------------------------------------------------------
ULONG
CUSBRequest::GetTransferType()
{
//
// call internal implementation
//
return InternalGetTransferType();
}
//----------------------------------------------------------------------------------------
ULONG
CUSBRequest::InternalGetTransferType()
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
ULONG TransferType;
//
// check if an irp is provided
//
if (m_Irp)
{
//
// get stack location
//
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
//
// get urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// check if there is a handle
//
if (Urb->UrbBulkOrInterruptTransfer.PipeHandle)
{
//
// cast to end point
//
EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
//
// end point is defined in the low byte of bmAttributes
//
TransferType = (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
}
else
{
//
// no pipe handle, assume it is a control transfer
//
TransferType = USB_ENDPOINT_TYPE_CONTROL;
}
}
else
{
//
// initialized with setup packet, must be a control transfer
//
TransferType = USB_ENDPOINT_TYPE_CONTROL;
}
//
// done
//
return TransferType;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::BuildControlTransferQueueHead(
PQUEUE_HEAD * OutHead)
{
NTSTATUS Status;
ULONG NumTransferDescriptors, Index;
PQUEUE_HEAD QueueHead;
//
// first allocate the queue head
//
Status = CreateQueueHead(&QueueHead);
if (!NT_SUCCESS(Status))
{
//
// failed to allocate queue head
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// create setup packet
//
Status = BuildSetupPacket();
if (!NT_SUCCESS(Status))
{
//
// failed to allocate setup packet
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// calculate num of transfer descriptors
//
NumTransferDescriptors = m_TransferBufferMDL != 0 ? 3 : 2;
//
// allocate transfer descriptors
//
for(Index = 0; Index < NumTransferDescriptors; Index++)
{
//
// allocate transfer descriptor
//
Status = CreateDescriptor(&m_TransferDescriptors[Index]);
if (!NT_SUCCESS(Status))
{
//
// failed to allocate transfer descriptor
//
return Status;
}
}
//
// now initialize the queue head
//
QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
//if (PipeHandle)
// QueueHead->EndPointCharacteristics.EndPointNumber = ((PUSB_ENDPOINT_DESCRIPTOR)PipeHandle)->bEndpointAddress & 0x0F;
QueueHead->Token.Bits.DataToggle = TRUE;
//
// setup descriptors
//
m_TransferDescriptors[0]->Token.Bits.PIDCode = PID_CODE_SETUP_TOKEN;
m_TransferDescriptors[0]->Token.Bits.TotalBytesToTransfer = sizeof(USB_DEFAULT_PIPE_SETUP_PACKET);
m_TransferDescriptors[0]->Token.Bits.DataToggle = FALSE;
if (m_TransferBufferMDL)
{
//
// setup in descriptor
//
m_TransferDescriptors[1]->Token.Bits.PIDCode = PID_CODE_IN_TOKEN;
m_TransferDescriptors[1]->Token.Bits.TotalBytesToTransfer = m_TransferBufferLength;
//
// setup out descriptor
//
m_TransferDescriptors[2]->Token.Bits.PIDCode = PID_CODE_OUT_TOKEN;
m_TransferDescriptors[2]->Token.Bits.TotalBytesToTransfer = 0;
//
// link descriptors
//
m_TransferDescriptors[0]->NextPointer = m_TransferDescriptors[1]->PhysicalAddr;
//
// special case, setup alternative next descriptor in case of error
// HAIKU links to dead descriptor
//
m_TransferDescriptors[0]->AlternateNextPointer = m_TransferDescriptors[2]->PhysicalAddr;
m_TransferDescriptors[1]->NextPointer = m_TransferDescriptors[2]->PhysicalAddr;
m_TransferDescriptors[1]->AlternateNextPointer = m_TransferDescriptors[2]->PhysicalAddr;
//
// interrupt on completion
//
m_TransferDescriptors[2]->Token.Bits.InterruptOnComplete = TRUE;
}
else
{
//
// no buffer, setup in descriptor
//
m_TransferDescriptors[1]->Token.Bits.PIDCode = PID_CODE_IN_TOKEN;
m_TransferDescriptors[1]->Token.Bits.TotalBytesToTransfer = 0;
//
// link descriptors
//
m_TransferDescriptors[0]->NextPointer = m_TransferDescriptors[1]->PhysicalAddr;
m_TransferDescriptors[0]->AlternateNextPointer = m_TransferDescriptors[1]->PhysicalAddr;
//
// interrupt on completion
//
m_TransferDescriptors[1]->Token.Bits.InterruptOnComplete = TRUE;
}
//
// FIXME: where put MDL virtual address?
//
//
// link setup packet into buffer - VIRTUAL Address!!!
//
m_TransferDescriptors[0]->BufferPointer[0] = (ULONG)PtrToUlong(m_DescriptorPacket);
//
// link transfer descriptors to queue head
//
QueueHead->NextPointer = m_TransferDescriptors[0]->PhysicalAddr;
//
// store result
//
*OutHead = QueueHead;
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::BuildBulkTransferQueueHead(
PQUEUE_HEAD * OutHead)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::CreateDescriptor(
PQUEUE_TRANSFER_DESCRIPTOR *OutDescriptor)
{
PQUEUE_TRANSFER_DESCRIPTOR Descriptor;
NTSTATUS Status;
PHYSICAL_ADDRESS TransferDescriptorPhysicalAddress;
//
// allocate descriptor
//
Status = m_DmaManager->Allocate(sizeof(QUEUE_TRANSFER_DESCRIPTOR), (PVOID*)&Descriptor, &TransferDescriptorPhysicalAddress);
if (!NT_SUCCESS(Status))
{
//
// failed to allocate transfer descriptor
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize transfer descriptor
//
Descriptor->NextPointer = TERMINATE_POINTER;
Descriptor->AlternateNextPointer = TERMINATE_POINTER;
Descriptor->Token.Bits.DataToggle = TRUE;
Descriptor->Token.Bits.ErrorCounter = 0x03;
Descriptor->Token.Bits.Active = TRUE;
Descriptor->PhysicalAddr = TransferDescriptorPhysicalAddress.LowPart;
//
// store result
//
*OutDescriptor = Descriptor;
//
// done
//
return Status;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::CreateQueueHead(
PQUEUE_HEAD *OutQueueHead)
{
PQUEUE_HEAD QueueHead;
PHYSICAL_ADDRESS QueueHeadPhysicalAddress;
NTSTATUS Status;
//
// allocate queue head
//
Status = m_DmaManager->Allocate(sizeof(QUEUE_HEAD), (PVOID*)&QueueHead, &QueueHeadPhysicalAddress);
if (!NT_SUCCESS(Status))
{
//
// failed to allocate queue head
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize queue head
//
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 QEDT
//
QueueHead->EndPointCharacteristics.QEDTDataToggleControl = FALSE;
//
// FIXME: check if High Speed Device
//
QueueHead->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
QueueHead->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03;
QueueHead->Token.DWord = 0;
QueueHead->Token.Bits.InterruptOnComplete = FALSE;
//
// FIXME check if that is really needed
//
QueueHead->PhysicalAddr = QueueHeadPhysicalAddress.LowPart;
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
ULONG
CUSBRequest::GetDeviceAddress()
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
PUSBDEVICE UsbDevice;
//
// check if there is an irp provided
//
if (!m_Irp)
{
//
// no irp is provided
// assume it is for device address 0
return 0;
}
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
//
// get contained urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// check if there is a pipe handle provided
//
if (Urb->UrbHeader.UsbdDeviceHandle)
{
//
// there is a device handle provided
//
UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
//
// return device address
//
return UsbDevice->GetDeviceAddress();
}
//
// no device handle provided, it is the host root bus
//
return 0;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::BuildSetupPacket()
{
NTSTATUS Status;
PHYSICAL_ADDRESS PhysicalAddress;
//
// FIXME: generate setup packet from urb request
//
PC_ASSERT(m_SetupPacket);
//
// allocate common buffer setup packet
//
Status = m_DmaManager->Allocate(sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), (PVOID*)&m_DescriptorPacket, &PhysicalAddress);
if (!NT_SUCCESS(Status))
{
//
// no memory
//
return Status;
}
if (m_SetupPacket)
{
//
// copy setup packet
//
RtlCopyMemory(m_DescriptorPacket, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
}
//
// done
//
return Status;
}

View file

@ -64,8 +64,6 @@ EHCI_Dispatch(
PIO_STACK_LOCATION IoStack; PIO_STACK_LOCATION IoStack;
NTSTATUS Status; NTSTATUS Status;
DPRINT1("EHCI_Dispatch\n");
// //
// get common device extension // get common device extension
// //
@ -106,19 +104,10 @@ EHCI_Dispatch(
// //
return DeviceExtension->Dispatcher->HandleDeviceControl(DeviceObject, Irp); return DeviceExtension->Dispatcher->HandleDeviceControl(DeviceObject, Irp);
} }
case IRP_MJ_CREATE:
{
//
// dispatch create request
//
Status = STATUS_SUCCESS;
break;
}
default: default:
{ {
DPRINT1("EHCI_Dispatch> Major %lu Minor %lu not supported\n", IoStack->MajorFunction, IoStack->MinorFunction); DPRINT1("EHCI_Dispatch> Major %lu Minor %lu unhandeled\n", IoStack->MajorFunction, IoStack->MinorFunction);
Status = STATUS_NOT_SUPPORTED; Status = STATUS_SUCCESS;
} }
} }