From c2d96ce7ff4ada63f06ce197423c0013d9c00c08 Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Fri, 3 Feb 2012 14:47:18 +0000 Subject: [PATCH] [USBOHCI] - Implement reseting pipe and clear pipe stall svn path=/branches/usb-bringup-trunk/; revision=55394 --- drivers/usb/usbohci/hardware.h | 1 + drivers/usb/usbohci/hub_controller.cpp | 194 +++++++++++++++++++++++++ drivers/usb/usbohci/interfaces.h | 18 +++ drivers/usb/usbohci/usb_device.cpp | 17 +++ drivers/usb/usbohci/usb_queue.cpp | 110 ++++++++++++++ drivers/usb/usbohci/usbohci.h | 1 + 6 files changed, 341 insertions(+) diff --git a/drivers/usb/usbohci/hardware.h b/drivers/usb/usbohci/hardware.h index b78a8daa990..e88c0941bbc 100644 --- a/drivers/usb/usbohci/hardware.h +++ b/drivers/usb/usbohci/hardware.h @@ -229,6 +229,7 @@ typedef struct _OHCI_ENDPOINT_DESCRIPTOR #define OHCI_ENDPOINT_SKIP 0x00004000 #define OHCI_ENDPOINT_SET_DEVICE_ADDRESS(s) (s) +#define OHCI_ENDPOINT_GET_DEVICE_ADDRESS(s) ((s) & 0xFF) #define OHCI_ENDPOINT_GET_ENDPOINT_NUMBER(s) (((s) >> 7) & 0xf) #define OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(s) ((s) << 7) #define OHCI_ENDPOINT_GET_MAX_PACKET_SIZE(s) (((s) >> 16) & 0x07ff) diff --git a/drivers/usb/usbohci/hub_controller.cpp b/drivers/usb/usbohci/hub_controller.cpp index add595eddd2..1325a84476d 100644 --- a/drivers/usb/usbohci/hub_controller.cpp +++ b/drivers/usb/usbohci/hub_controller.cpp @@ -70,6 +70,9 @@ public: NTSTATUS HandleClassEndpoint(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleBulkOrInterruptTransfer(IN OUT PIRP Irp, PURB Urb); NTSTATUS HandleIsochronousTransfer(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleClearStall(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleSyncResetAndClearStall(IN OUT PIRP Irp, PURB Urb); + NTSTATUS HandleAbortPipe(IN OUT PIRP Irp, PURB Urb); friend VOID StatusChangeEndpointCallBack(PVOID Context); @@ -1692,6 +1695,187 @@ CHubController::HandleClassEndpoint( return Status; } +NTSTATUS +CHubController::HandleSyncResetAndClearStall( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status = STATUS_SUCCESS; + PUSBDEVICE UsbDevice; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + ULONG Type; + + // + // sanity check + // + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST)); + PC_ASSERT(Urb->UrbPipeRequest.PipeHandle); + + // + // check if this is a valid usb device handle + // + if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) + { + DPRINT1("HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // get endpoint descriptor + // + EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle; + + // + // get type + // + Type = (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK); + if (Type != USB_ENDPOINT_TYPE_ISOCHRONOUS) + { + // + // clear stall + // + Status = HandleClearStall(Irp, Urb); + } + DPRINT1("URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL Status %x\n", Status); + + // + // FIXME reset data toggle + // + + // + // done + // + return Status; +} + +NTSTATUS +CHubController::HandleAbortPipe( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + PUSBDEVICE UsbDevice; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + + + // + // sanity check + // + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST)); + PC_ASSERT(Urb->UrbPipeRequest.PipeHandle); + + // + // check if this is a valid usb device handle + // + if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) + { + DPRINT1("HandleAbortPipe invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // get endpoint descriptor + // + EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle; + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + + + // + // issue request + // + Status = UsbDevice->AbortPipe(EndpointDescriptor); + DPRINT1("URB_FUNCTION_ABORT_PIPE Status %x\n", Status); + + // + // done + // + return Status; +} + + +//----------------------------------------------------------------------------------------- +NTSTATUS +CHubController::HandleClearStall( + IN OUT PIRP Irp, + IN OUT PURB Urb) +{ + USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup; + NTSTATUS Status; + PUSBDEVICE UsbDevice; + PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + + + // + // sanity check + // + PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle); + PC_ASSERT(Urb->UrbHeader.Length == sizeof(struct _URB_PIPE_REQUEST)); + PC_ASSERT(Urb->UrbPipeRequest.PipeHandle); + + // + // check if this is a valid usb device handle + // + if (!ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle))) + { + DPRINT1("HandleClearStall invalid device handle %p\n", Urb->UrbHeader.UsbdDeviceHandle); + + // + // invalid device handle + // + return STATUS_DEVICE_NOT_CONNECTED; + } + + // + // get endpoint descriptor + // + EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbPipeRequest.PipeHandle; + + // + // get device + // + UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle); + DPRINT1("URB_FUNCTION_SYNC_CLEAR_STALL\n"); + + // + // initialize setup packet + // + CtrlSetup.bmRequestType.B = 0x02; + CtrlSetup.bRequest = USB_REQUEST_CLEAR_FEATURE; + CtrlSetup.wValue.W = USB_FEATURE_ENDPOINT_STALL; + CtrlSetup.wIndex.W = EndpointDescriptor->bEndpointAddress; + CtrlSetup.wLength = 0; + CtrlSetup.wValue.W = 0; + + // + // issue request + // + Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, 0, 0); + + DPRINT1("URB_FUNCTION_CLEAR_STALL Status %x\n", Status); + + // + // done + // + return Status; +} + + //----------------------------------------------------------------------------------------- NTSTATUS CHubController::HandleClassInterface( @@ -1813,6 +1997,16 @@ CHubController::HandleDeviceControl( switch (Urb->UrbHeader.Function) { + case URB_FUNCTION_SYNC_RESET_PIPE: + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: + Status = HandleSyncResetAndClearStall(Irp, Urb); + break; + case URB_FUNCTION_ABORT_PIPE: + Status = HandleAbortPipe(Irp, Urb); + break; + case URB_FUNCTION_SYNC_CLEAR_STALL: + Status = HandleClearStall(Irp, Urb); + break; case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: Status = HandleGetDescriptorFromInterface(Irp, Urb); break; diff --git a/drivers/usb/usbohci/interfaces.h b/drivers/usb/usbohci/interfaces.h index 90180077770..c8b50ffc54f 100644 --- a/drivers/usb/usbohci/interfaces.h +++ b/drivers/usb/usbohci/interfaces.h @@ -556,6 +556,14 @@ DECLARE_INTERFACE_(IUSBQueue, IUnknown) virtual VOID TransferDescriptorCompletionCallback(ULONG TransferDescriptorLogicalAddress) = 0; + +//----------------------------------------------------------------------------------------- +// +// AbortDevicePipe +// +// Description: aborts all pending requsts of an device + + virtual NTSTATUS AbortDevicePipe(UCHAR DeviceAddress, IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) = 0; }; typedef IUSBQueue *PUSBQUEUE; @@ -809,6 +817,16 @@ DECLARE_INTERFACE_(IUSBDevice, IUnknown) virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle, IN OUT PUSBD_INTERFACE_INFORMATION Interface) = 0; + + +//----------------------------------------------------------------------------------------- +// +// AbortPipe +// +// Description: aborts all pending requsts + + virtual NTSTATUS AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) = 0; + }; typedef IUSBDevice *PUSBDEVICE; diff --git a/drivers/usb/usbohci/usb_device.cpp b/drivers/usb/usbohci/usb_device.cpp index b28cfe93d2e..a8e3253fef8 100644 --- a/drivers/usb/usbohci/usb_device.cpp +++ b/drivers/usb/usbohci/usb_device.cpp @@ -52,6 +52,7 @@ public: virtual NTSTATUS SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, OUT ULONG BufferLength, OUT PVOID Buffer); virtual NTSTATUS SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, IN PUSBD_INTERFACE_INFORMATION Interface, OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle); virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle, IN OUT PUSBD_INTERFACE_INFORMATION Interface); + virtual NTSTATUS AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor); // local function virtual NTSTATUS CommitIrp(PIRP Irp); @@ -1174,6 +1175,22 @@ CUSBDevice::SelectInterface( return Status; } +NTSTATUS +CUSBDevice::AbortPipe( + IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) +{ + // + // let it handle usb queue + // + ASSERT(m_Queue); + ASSERT(m_DeviceAddress); + + // + // done + // + return m_Queue->AbortDevicePipe(m_DeviceAddress, EndpointDescriptor); +} + //---------------------------------------------------------------------------------------- NTSTATUS CreateUSBDevice( diff --git a/drivers/usb/usbohci/usb_queue.cpp b/drivers/usb/usbohci/usb_queue.cpp index 2651c15cfc8..dabc4586a6b 100644 --- a/drivers/usb/usbohci/usb_queue.cpp +++ b/drivers/usb/usbohci/usb_queue.cpp @@ -40,6 +40,7 @@ public: virtual NTSTATUS CancelRequests(); virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest); virtual VOID TransferDescriptorCompletionCallback(ULONG TransferDescriptorLogicalAddress); + virtual NTSTATUS AbortDevicePipe(UCHAR DeviceAddress, IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor); // local functions BOOLEAN IsTransferDescriptorInEndpoint(IN POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN ULONG TransferDescriptorLogicalAddress); @@ -740,6 +741,115 @@ CUSBQueue::FindInterruptEndpointDescriptor( return m_InterruptEndpoints[Index]; } +NTSTATUS +CUSBQueue::AbortDevicePipe( + IN UCHAR DeviceAddress, + IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor) +{ + POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor, CurrentDescriptor, PreviousDescriptor, TempDescriptor; + ULONG Type; + POHCI_GENERAL_TD TransferDescriptor; + + // + // get type + // + Type = (EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK); + + // + // check type + // + if (Type == USB_ENDPOINT_TYPE_BULK) + { + // + // get head descriptor + // + HeadDescriptor = m_BulkHeadEndpointDescriptor; + } + else if (Type == USB_ENDPOINT_TYPE_CONTROL) + { + // + // get head descriptor + // + HeadDescriptor = m_ControlHeadEndpointDescriptor; + } + else if (Type == USB_ENDPOINT_TYPE_INTERRUPT) + { + // + // get head descriptor + // + HeadDescriptor = FindInterruptEndpointDescriptor(EndpointDescriptor->bInterval); + ASSERT(HeadDescriptor); + } + else if (Type == USB_ENDPOINT_TYPE_ISOCHRONOUS) + { + UNIMPLEMENTED + return STATUS_NOT_IMPLEMENTED; + } + + // + // FIXME should disable list processing + // + + // + // now remove all endpoints + // + ASSERT(HeadDescriptor); + CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor->NextDescriptor; + PreviousDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)HeadDescriptor; + + while(CurrentDescriptor) + { + if ((CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HEAD_MASK) == CurrentDescriptor->TailPhysicalDescriptor || (CurrentDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED)) + { + // + // cleanup endpoint + // + TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor; + CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor); + + // + // use next descriptor + // + CurrentDescriptor = TempDescriptor; + } + + if (!CurrentDescriptor) + break; + + if (CurrentDescriptor->HeadPhysicalDescriptor) + { + TransferDescriptor = (POHCI_GENERAL_TD)CurrentDescriptor->HeadLogicalDescriptor; + ASSERT(TransferDescriptor); + + if ((OHCI_ENDPOINT_GET_ENDPOINT_NUMBER(TransferDescriptor->Flags) == (EndpointDescriptor->bEndpointAddress & 0xF)) && + (OHCI_ENDPOINT_GET_DEVICE_ADDRESS(TransferDescriptor->Flags) == DeviceAddress)) + { + // + // cleanup endpoint + // + TempDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor; + CleanupEndpointDescriptor(CurrentDescriptor, PreviousDescriptor); + // + // use next descriptor + // + CurrentDescriptor = TempDescriptor; + } + } + + if (!CurrentDescriptor) + break; + + PreviousDescriptor = CurrentDescriptor; + CurrentDescriptor = (POHCI_ENDPOINT_DESCRIPTOR)CurrentDescriptor->NextDescriptor; + } + + // + // done + // + return STATUS_SUCCESS; +} + + NTSTATUS CreateUSBQueue( PUSBQUEUE *OutUsbQueue) diff --git a/drivers/usb/usbohci/usbohci.h b/drivers/usb/usbohci/usbohci.h index 59d27b9bcc4..6eab4ba6045 100644 --- a/drivers/usb/usbohci/usbohci.h +++ b/drivers/usb/usbohci/usbohci.h @@ -7,6 +7,7 @@ #include #include #include +#include extern "C" -- 2.17.1