diff --git a/drivers/usb/usbehci_new/CMakeLists.txt b/drivers/usb/usbehci_new/CMakeLists.txt index 09f8928e929..a552101e3d1 100644 --- a/drivers/usb/usbehci_new/CMakeLists.txt +++ b/drivers/usb/usbehci_new/CMakeLists.txt @@ -7,6 +7,7 @@ add_definitions(-D_WIN32_WINNT=0x600) add_library(usbehci SHARED usbehci.cpp usb_device.cpp + usb_request.cpp usb_queue.cpp hcd_controller.cpp hardware.cpp diff --git a/drivers/usb/usbehci_new/hcd_controller.cpp b/drivers/usb/usbehci_new/hcd_controller.cpp index 4ed974ba856..9146dae4b60 100644 --- a/drivers/usb/usbehci_new/hcd_controller.cpp +++ b/drivers/usb/usbehci_new/hcd_controller.cpp @@ -327,8 +327,11 @@ CHCDController::HandleDeviceControl( 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); } @@ -552,7 +555,6 @@ CHCDController::HandlePnp( } default: { - DPRINT1("CHCDController::HandlePnp Dispatch to lower device object %lx\n", IoStack->MinorFunction); // // forward irp to next device object // diff --git a/drivers/usb/usbehci_new/hub_controller.cpp b/drivers/usb/usbehci_new/hub_controller.cpp index a247448e6c3..c1c3df128ff 100644 --- a/drivers/usb/usbehci_new/hub_controller.cpp +++ b/drivers/usb/usbehci_new/hub_controller.cpp @@ -61,6 +61,8 @@ public: NTSTATUS HandleGetStatusFromDevice(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleSelectConfiguration(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleClassOther(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb); + // constructor / destructor CHubController(IUnknown *OuterUnknown){} @@ -155,6 +157,20 @@ 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 @@ -653,7 +669,9 @@ CHubController::HandlePnp( } default: { - DPRINT1("CHubController::HandlePnp Unhandeled %x\n", IoStack->MinorFunction); + // + // ignore request with default status + // Status = Irp->IoStatus.Status; break; } @@ -682,6 +700,15 @@ CHubController::HandlePower( IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_NOT_IMPLEMENTED; } +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleBulkOrInterruptTransfer( + IN OUT PIRP Irp, + PURB Urb) +{ + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; +} //----------------------------------------------------------------------------------------- NTSTATUS @@ -689,11 +716,143 @@ CHubController::HandleClassOther( IN OUT PIRP Irp, 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; } @@ -862,7 +1021,6 @@ CHubController::HandleGetDescriptor( if (Urb->UrbHeader.UsbdDeviceHandle == NULL) { - DPRINT1("Root Hub descriptor\n"); // // copy root hub device descriptor // @@ -960,13 +1118,6 @@ CHubController::HandleDeviceControl( // 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 // @@ -980,8 +1131,6 @@ CHubController::HandleDeviceControl( Urb = (PURB)IoStack->Parameters.Others.Argument1; 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) { case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: @@ -999,6 +1148,12 @@ CHubController::HandleDeviceControl( case URB_FUNCTION_CLASS_OTHER: Status = HandleClassOther(Irp, Urb); 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 @@ -1007,7 +1162,7 @@ CHubController::HandleDeviceControl( } 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) { @@ -1032,7 +1187,7 @@ CHubController::HandleDeviceControl( } 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 @@ -1061,7 +1216,7 @@ CHubController::HandleDeviceControl( } 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 @@ -1082,6 +1237,14 @@ CHubController::HandleDeviceControl( Irp->IoStatus.Information = sizeof(ULONG); 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; @@ -1921,7 +2084,37 @@ USBHI_GetControllerInformation( ULONG ControllerInformationBufferLength, 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; } diff --git a/drivers/usb/usbehci_new/interfaces.h b/drivers/usb/usbehci_new/interfaces.h index 743dabcc108..df2636943e2 100644 --- a/drivers/usb/usbehci_new/interfaces.h +++ b/drivers/usb/usbehci_new/interfaces.h @@ -312,6 +312,8 @@ typedef IDMAMemoryManager *PDMAMEMORYMANAGER; // CancelCallback routine is invoked. // +struct _QUEUE_HEAD; + DECLARE_INTERFACE_(IUSBRequest, IUnknown) { DEFINE_ABSTRACT_UNKNOWN() @@ -324,44 +326,39 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown) // If there is a TransferBuffer, the TransferBufferLength contains the length of the buffer - virtual NTSTATUS InitializeWithSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, - IN ULONG TransferBufferLength, - IN PVOID TransferBuffer) = 0; - -// -//TODO: find required parameters for different packet types -// - + virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, + IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, + IN OUT ULONG TransferBufferLength, + IN OUT PMDL TransferBuffer) = 0; //----------------------------------------------------------------------------------------- // -// 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 -// If an irp is passed, then it is completed with status code of the -// CompletionCallback or CancelCallback -// If an event is passed, then the event is signaled +// Description: sets up completion event which is signaled when the +// request is completed or cancelled - virtual NTSTATUS SetCompletionDetails(IN OPTIONAL PIRP Irp, - IN OPTIONAL PKEVENT Event) = 0; + virtual NTSTATUS SetCompletionEvent(IN PKEVENT Event) = 0; //----------------------------------------------------------------------------------------- // // 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 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; +//----------------------------------------------------------------------------------------- +// +// 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; diff --git a/drivers/usb/usbehci_new/usb_device.cpp b/drivers/usb/usbehci_new/usb_device.cpp index db253bd0753..9190a106b10 100644 --- a/drivers/usb/usbehci_new/usb_device.cpp +++ b/drivers/usb/usbehci_new/usb_device.cpp @@ -68,6 +68,7 @@ protected: USB_DEVICE_DESCRIPTOR m_DeviceDescriptor; ULONG m_PortStatus; PUSBQUEUE m_Queue; + PDMAMEMORYMANAGER m_DmaManager; }; //---------------------------------------------------------------------------------------- @@ -124,6 +125,21 @@ CUSBDevice::Initialize( 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 // @@ -293,7 +309,7 @@ CUSBDevice::SetDeviceAddress( // initialize request // CtrlSetup.bRequest = USB_REQUEST_SET_ADDRESS; - CtrlSetup.wValue.W = DeviceAddress; + CtrlSetup.wValue.W = (USHORT)DeviceAddress; // // set device address @@ -386,6 +402,8 @@ CUSBDevice::CommitSetupPacket( PUSBREQUEST Request; KEVENT Event; BOOLEAN Wait = FALSE; + PMDL Mdl = 0; + if (!m_Queue) { @@ -409,10 +427,12 @@ CUSBDevice::CommitSetupPacket( return Status; } + /* FIXME build MDL */ + // // initialize request // - Status = Request->InitializeWithSetupPacket(Packet, BufferLength, Buffer); + Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, BufferLength, Mdl); if (!NT_SUCCESS(Status)) { // @@ -439,7 +459,7 @@ CUSBDevice::CommitSetupPacket( // // set completion details // - Status = Request->SetCompletionDetails(Irp, pEvent); + Status = Request->SetCompletionEvent(pEvent); if (!NT_SUCCESS(Status)) { // diff --git a/drivers/usb/usbehci_new/usb_request.cpp b/drivers/usb/usbehci_new/usb_request.cpp new file mode 100644 index 00000000000..18a3a1a8205 --- /dev/null +++ b/drivers/usb/usbehci_new/usb_request.cpp @@ -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; +} + diff --git a/drivers/usb/usbehci_new/usbehci.cpp b/drivers/usb/usbehci_new/usbehci.cpp index 32b3baab6fd..2793eee8927 100644 --- a/drivers/usb/usbehci_new/usbehci.cpp +++ b/drivers/usb/usbehci_new/usbehci.cpp @@ -64,8 +64,6 @@ EHCI_Dispatch( PIO_STACK_LOCATION IoStack; NTSTATUS Status; - DPRINT1("EHCI_Dispatch\n"); - // // get common device extension // @@ -106,19 +104,10 @@ EHCI_Dispatch( // return DeviceExtension->Dispatcher->HandleDeviceControl(DeviceObject, Irp); } - case IRP_MJ_CREATE: - { - // - // dispatch create request - // - Status = STATUS_SUCCESS; - - break; - } default: { - DPRINT1("EHCI_Dispatch> Major %lu Minor %lu not supported\n", IoStack->MajorFunction, IoStack->MinorFunction); - Status = STATUS_NOT_SUPPORTED; + DPRINT1("EHCI_Dispatch> Major %lu Minor %lu unhandeled\n", IoStack->MajorFunction, IoStack->MinorFunction); + Status = STATUS_SUCCESS; } }