[USBOHCI]

- Check if the transfer descriptors reported errors and propagate the error in the urb status field
- OHCI now reports error which the class driver are handling
- Allocate device descriptor from non paged pool to prevent possible alignment problems
- Fix checking of completed transfer descriptors
- Fix double freeing of descriptors
- Cleanup endpoints when the halted bit is set by the host controllers
- Check for the endpoint direction in the data descriptor
- Setup descriptor needs buffer rounding set

svn path=/branches/usb-bringup-trunk/; revision=55389
This commit is contained in:
Johannes Anderwald 2012-02-03 09:52:29 +00:00
parent b1587061be
commit 4cbccecd5c
6 changed files with 203 additions and 21 deletions

View file

@ -1457,6 +1457,8 @@ InterruptServiceRoutine(
// the interrupt was not caused by DoneHead update
// check if something important happened
//
DPRINT1("InterruptStatus %x InterruptEnable %x\n", READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_STATUS_OFFSET)),
READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_ENABLE_OFFSET)));
Status = READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_STATUS_OFFSET)) & READ_REGISTER_ULONG((PULONG)((PUCHAR)This->m_Base + OHCI_INTERRUPT_ENABLE_OFFSET)) & (~OHCI_WRITEBACK_DONE_HEAD);
if (Status == 0)
{

View file

@ -239,7 +239,8 @@ typedef struct _OHCI_ENDPOINT_DESCRIPTOR
#define OHCI_ENDPOINT_DIRECTION_IN 0x00001000
#define OHCI_ENDPOINT_GENERAL_FORMAT 0x00000000
#define OHCI_ENDPOINT_ISOCHRONOUS_FORMAT 0x00008000
#define OHCI_ENDPOINT_HEAD_MASK 0xfffffffc
#define OHCI_ENDPOINT_HALTED 0x00000001
//
// Maximum port count set by OHCI
//

View file

@ -1763,8 +1763,13 @@ CHubController::HandleClassInterface(
//
// assert on failure
//
PC_ASSERT(NT_SUCCESS(Status));
if (!NT_SUCCESS(Status))
{
//
// display error
//
DPRINT1("URB_FUNCTION_CLASS_INTERFACE failed with Urb Status %x\n", Urb->UrbHeader.Status);
}
//
// done

View file

@ -598,11 +598,24 @@ CUSBDevice::CreateDeviceDescriptor()
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
PMDL Mdl;
NTSTATUS Status;
PVOID DeviceDescriptor;
//
// allocate descriptor page aligned
//
DeviceDescriptor = ExAllocatePool(NonPagedPool, PAGE_SIZE);
if (!DeviceDescriptor)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// zero descriptor
//
RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
RtlZeroMemory(DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
//
@ -616,7 +629,7 @@ CUSBDevice::CreateDeviceDescriptor()
//
// allocate mdl describing the device descriptor
//
Mdl = IoAllocateMdl(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR), FALSE, FALSE, 0);
Mdl = IoAllocateMdl(DeviceDescriptor, PAGE_SIZE, FALSE, FALSE, 0);
if (!Mdl)
{
//
@ -642,12 +655,22 @@ CUSBDevice::CreateDeviceDescriptor()
if (NT_SUCCESS(Status))
{
//
// copy back device descriptor
//
RtlCopyMemory(&m_DeviceDescriptor, DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
//
// informal dbg print
//
DumpDeviceDescriptor(&m_DeviceDescriptor);
}
//
// free item
//
ExFreePool(DeviceDescriptor);
//
// done
//

View file

@ -363,7 +363,7 @@ CUSBQueue::FindTransferDescriptorInEndpoint(
//
// check if the transfer descriptor is inside the list
//
if (IsTransferDescriptorInEndpoint(EndpointDescriptor, TransferDescriptorLogicalAddress))
if ((EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HEAD_MASK) == EndpointDescriptor->TailPhysicalDescriptor || (EndpointDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_HALTED))
{
//
// found endpoint
@ -584,13 +584,6 @@ CUSBQueue::CleanupEndpointDescriptor(
//
Request->FreeEndpointDescriptor(EndpointDescriptor);
//
// FIXME: check if complete
//
//ASSERT(Request->IsRequestComplete());
Request->FreeEndpointDescriptor(EndpointDescriptor);
//
// release request
//

View file

@ -64,6 +64,8 @@ public:
NTSTATUS CreateIsochronousTransferDescriptor(OUT POHCI_ISO_TD *OutDescriptor, ULONG FrameCount);
UCHAR GetEndpointAddress();
USHORT GetMaxPacketSize();
VOID CheckError(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
// constructor / destructor
CUSBRequest(IUnknown *OuterUnknown){}
@ -968,7 +970,6 @@ CUSBRequest::AllocateEndpointDescriptor(
}
//
// FIXME: detect type
//
@ -1269,7 +1270,37 @@ CUSBRequest::BuildControlTransferDescriptor(
//
// initialize data descriptor
//
DataDescriptor->Flags = OHCI_TD_BUFFER_ROUNDING| OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY | OHCI_TD_DIRECTION_PID_IN;
DataDescriptor->Flags = OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE) | OHCI_TD_TOGGLE_CARRY | OHCI_TD_TOGGLE_1;
if (m_EndpointDescriptor)
{
if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->bEndpointAddress))
{
//
// direction out
//
DataDescriptor->Flags |= OHCI_TD_DIRECTION_PID_OUT;
}
else
{
//
// direction in
//
DataDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN;
}
}
else
{
//
// no end point address provided - assume its an in direction
//
DataDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN;
}
//
// FIXME verify short packets are ok
//
//DataDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
//
// store physical address of buffer
@ -1282,7 +1313,7 @@ CUSBRequest::BuildControlTransferDescriptor(
//
// initialize setup descriptor
//
SetupDescriptor->Flags = OHCI_TD_DIRECTION_PID_SETUP | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_0 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);
SetupDescriptor->Flags = OHCI_TD_BUFFER_ROUNDING | OHCI_TD_DIRECTION_PID_SETUP | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_0 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);
if (m_SetupPacket)
{
@ -1560,6 +1591,134 @@ CUSBRequest::FreeEndpointDescriptor(
}
VOID
CUSBRequest::CheckError(
struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
{
POHCI_GENERAL_TD TransferDescriptor;
ULONG ConditionCode;
PURB Urb;
PIO_STACK_LOCATION IoStack;
//
// set status code
//
m_NtStatusCode = STATUS_SUCCESS;
m_UrbStatusCode = USBD_STATUS_SUCCESS;
if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
{
//
// FIXME: handle isochronous support
//
ASSERT(FALSE);
}
else
{
//
// get first general transfer descriptor
//
TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
while(TransferDescriptor)
{
//
// the descriptor must have been processed
//
ASSERT(OHCI_TD_GET_CONDITION_CODE(TransferDescriptor->Flags) != OHCI_TD_CONDITION_NOT_ACCESSED);
//
// get condition code
//
ConditionCode = OHCI_TD_GET_CONDITION_CODE(TransferDescriptor->Flags);
if (ConditionCode != OHCI_TD_CONDITION_NO_ERROR)
{
//
// FIXME status code
//
m_NtStatusCode = STATUS_UNSUCCESSFUL;
switch(ConditionCode)
{
case OHCI_TD_CONDITION_CRC_ERROR:
DPRINT1("OHCI_TD_CONDITION_CRC_ERROR detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_CRC;
break;
case OHCI_TD_CONDITION_BIT_STUFFING:
DPRINT1("OHCI_TD_CONDITION_BIT_STUFFING detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_BTSTUFF;
break;
case OHCI_TD_CONDITION_TOGGLE_MISMATCH:
DPRINT1("OHCI_TD_CONDITION_TOGGLE_MISMATCH detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_DATA_TOGGLE_MISMATCH;
break;
case OHCI_TD_CONDITION_STALL:
DPRINT1("OHCI_TD_CONDITION_STALL detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_STALL_PID;
break;
case OHCI_TD_CONDITION_NO_RESPONSE:
DPRINT1("OHCI_TD_CONDITION_NO_RESPONSE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_DEV_NOT_RESPONDING;
break;
case OHCI_TD_CONDITION_PID_CHECK_FAILURE:
DPRINT1("OHCI_TD_CONDITION_PID_CHECK_FAILURE detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_PID_CHECK_FAILURE;
break;
case OHCI_TD_CONDITION_UNEXPECTED_PID:
DPRINT1("OHCI_TD_CONDITION_UNEXPECTED_PID detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_UNEXPECTED_PID;
break;
case OHCI_TD_CONDITION_DATA_OVERRUN:
DPRINT1("OHCI_TD_CONDITION_DATA_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_DATA_OVERRUN;
break;
case OHCI_TD_CONDITION_DATA_UNDERRUN:
if (m_Irp)
{
//
// get current irp stack location
//
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
//
// get urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
if(Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_SHORT_TRANSFER_OK)
{
//
// short packets are ok
//
ASSERT(Urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER);
m_NtStatusCode = STATUS_SUCCESS;
break;
}
}
DPRINT1("OHCI_TD_CONDITION_DATA_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_DATA_UNDERRUN;
break;
case OHCI_TD_CONDITION_BUFFER_OVERRUN:
DPRINT1("OHCI_TD_CONDITION_BUFFER_OVERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_BUFFER_OVERRUN;
break;
case OHCI_TD_CONDITION_BUFFER_UNDERRUN:
DPRINT1("OHCI_TD_CONDITION_BUFFER_UNDERRUN detected in TransferDescriptor TransferDescriptor %p\n", TransferDescriptor);
m_UrbStatusCode = USBD_STATUS_BUFFER_UNDERRUN;
break;
}
}
//
// get next
//
TransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
}
}
}
VOID
CUSBRequest::CompletionCallback(
struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
@ -1570,17 +1729,16 @@ CUSBRequest::CompletionCallback(
DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
//
// set status code
// check for errors
//
m_NtStatusCode = STATUS_SUCCESS;
m_UrbStatusCode = USBD_STATUS_SUCCESS;
CheckError(OutDescriptor);
if (m_Irp)
{
//
// set irp completion status
//
m_Irp->IoStatus.Status = STATUS_SUCCESS; //FIXME
m_Irp->IoStatus.Status = m_NtStatusCode;
//
// get current irp stack location
@ -1595,7 +1753,7 @@ CUSBRequest::CompletionCallback(
//
// store urb status
//
Urb->UrbHeader.Status = USBD_STATUS_SUCCESS; //FIXME
Urb->UrbHeader.Status = m_UrbStatusCode;
//
// Check if the MDL was created