[USBOHCI]

- Remove dead code
- Silence traces
- Pass status & DoneHead as parameters to dpc routine
- Move IUSBRequest cleanup code into new function and use it for bulk / control transfer cleanup
- Fix bugs in AllocateEndpointDescriptor. It did not take the device address into account. It also did not respect the direction of the descriptor
- Implement support for bulk transfer requests
- Handle irp completion in CompletionCallback
- Tested in Windows XP SP3 + Vbox 4.04 + USB2.0 disabled + ReactOS usbstor + USB mass storage device
- OHCI Mass storage support is now also ready
- Next interrupt transfers

svn path=/branches/usb-bringup/; revision=51917
This commit is contained in:
Johannes Anderwald 2011-05-26 02:15:11 +00:00
parent 2c6077dc50
commit 667b425b6c
5 changed files with 392 additions and 79 deletions

View file

@ -697,8 +697,6 @@ CUSBHardwareDevice::HeadEndpointDescriptorModified(
//
// notify controller
//
//WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_HEAD_ED_OFFSET), m_ControlEndpointDescriptor->NextPhysicalEndpoint);
//WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_CONTROL_CURRENT_ED_OFFSET), m_ControlEndpointDescriptor->NextPhysicalEndpoint);
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Value | OHCI_CONTROL_LIST_FILLED);
}
else if (Type == USB_ENDPOINT_TYPE_BULK)
@ -708,12 +706,6 @@ CUSBHardwareDevice::HeadEndpointDescriptorModified(
//
WRITE_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET), Value | OHCI_BULK_LIST_FILLED);
}
Value = READ_REGISTER_ULONG((PULONG)((PUCHAR)m_Base + OHCI_COMMAND_STATUS_OFFSET));
DPRINT1("HeadEndpointDescriptorModified Value %x Type %x\n", Value, Type);
}
NTSTATUS
@ -1191,7 +1183,7 @@ InterruptServiceRoutine(
//
This = (CUSBHardwareDevice*) ServiceContext;
DPRINT1("InterruptServiceRoutine\n");
DPRINT("InterruptServiceRoutine\n");
//
// get done head
@ -1246,6 +1238,7 @@ InterruptServiceRoutine(
// head completed
//
Acknowledge |= OHCI_WRITEBACK_DONE_HEAD;
This->m_HCCA->DoneHead = 0;
}
if (Status & OHCI_RESUME_DETECTED)
@ -1296,8 +1289,8 @@ InterruptServiceRoutine(
//
// defer processing
//
DPRINT1("Status %x\n", Status);
KeInsertQueueDpc(&This->m_IntDpcObject, This, (PVOID)Status);
DPRINT("Status %x Acknowledge %x\n", Status, Acknowledge);
KeInsertQueueDpc(&This->m_IntDpcObject, (PVOID)Status, (PVOID)(DoneHead & ~1));
//
// interrupt handled
@ -1321,23 +1314,14 @@ OhciDefferedRoutine(
//
// get parameters
//
This = (CUSBHardwareDevice*) SystemArgument1;
CStatus = (ULONG) SystemArgument2;
This = (CUSBHardwareDevice*)DeferredContext;
CStatus = (ULONG) SystemArgument1;
DoneHead = (ULONG)SystemArgument2;
DPRINT1("OhciDefferedRoutine Status %x\n", CStatus);
DPRINT("OhciDefferedRoutine Status %x\n", CStatus);
if (CStatus & OHCI_WRITEBACK_DONE_HEAD)
{
//
// descriptor completion, get done head
//
DoneHead = This->m_HCCA->DoneHead;
//
// clear out lower bits, ed are 16 byte aligned
//
DoneHead &= ~0xF;
//
// notify queue of event
//

View file

@ -216,6 +216,8 @@ typedef struct _OHCI_ENDPOINT_DESCRIPTOR
#define OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(s) ((s) << 16)
#define OHCI_ENDPOINT_LOW_SPEED 0x00002000
#define OHCI_ENDPOINT_FULL_SPEED 0x00000000
#define OHCI_ENDPOINT_DIRECTION_OUT 0x00000800
#define OHCI_ENDPOINT_DIRECTION_IN 0x00001000
//
// Maximum port count set by OHCI

View file

@ -443,6 +443,14 @@ DECLARE_INTERFACE_(IUSBRequest, IUnknown)
// Description: notifies request that the endpoint descriptor is complete
virtual VOID CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor) = 0;
//-----------------------------------------------------------------------------------------
//
// FreeEndpointDescriptor
//
// Description: frees the associated endpoint descriptor and its general descriptors
virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor) = 0;
};

View file

@ -44,6 +44,7 @@ public:
// local functions
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);
VOID CleanupEndpointDescriptor(POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor);
// constructor / destructor
CUSBQueue(IUnknown *OuterUnknown){}
@ -127,7 +128,7 @@ CUSBQueue::AddUSBRequest(
POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor;
POHCI_ENDPOINT_DESCRIPTOR Descriptor;
DPRINT1("CUSBQueue::AddUSBRequest\n");
DPRINT("CUSBQueue::AddUSBRequest\n");
//
// sanity check
@ -146,11 +147,11 @@ CUSBQueue::AddUSBRequest(
{
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
case USB_ENDPOINT_TYPE_INTERRUPT:
case USB_ENDPOINT_TYPE_BULK:
/* NOT IMPLEMENTED IN QUEUE */
Status = STATUS_NOT_SUPPORTED;
break;
case USB_ENDPOINT_TYPE_CONTROL:
case USB_ENDPOINT_TYPE_BULK:
Status = STATUS_SUCCESS;
break;
default:
@ -228,12 +229,14 @@ CUSBQueue::AddUSBRequest(
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);
//
// notify hardware of our request
//
m_Hardware->HeadEndpointDescriptorModified(Type);
DPRINT1("Request %x %x added to queue\n", Descriptor, Descriptor->PhysicalAddress);
return STATUS_SUCCESS;
@ -356,6 +359,47 @@ CUSBQueue::IsTransferDescriptorInEndpoint(
return FALSE;
}
VOID
CUSBQueue::CleanupEndpointDescriptor(
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor,
POHCI_ENDPOINT_DESCRIPTOR PreviousEndpointDescriptor)
{
PUSBREQUEST Request;
//
// FIXME: verify unlinking process
//
PreviousEndpointDescriptor->NextDescriptor = EndpointDescriptor->NextDescriptor;
PreviousEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->NextPhysicalEndpoint;
//
// get corresponding request
//
Request = PUSBREQUEST(EndpointDescriptor->Request);
ASSERT(Request);
//
// notify of completion
//
Request->CompletionCallback(EndpointDescriptor);
//
// free endpoint descriptor
//
Request->FreeEndpointDescriptor(EndpointDescriptor);
//
// FIXME: check if complete
//
//ASSERT(Request->IsRequestComplete());
//
// release request
//
Request->Release();
}
VOID
CUSBQueue::TransferDescriptorCompletionCallback(
@ -363,7 +407,8 @@ CUSBQueue::TransferDescriptorCompletionCallback(
{
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor, PreviousEndpointDescriptor;
NTSTATUS Status;
PUSBREQUEST Request;
DPRINT("CUSBQueue::TransferDescriptorCompletionCallback transfer descriptor %x\n", TransferDescriptorLogicalAddress);
//
// find transfer descriptor in control list
@ -372,32 +417,39 @@ CUSBQueue::TransferDescriptorCompletionCallback(
if (NT_SUCCESS(Status))
{
//
// FIXME: make sure this is ok
// unlink descriptor
// cleanup endpoint
//
PreviousEndpointDescriptor->NextDescriptor = EndpointDescriptor->NextDescriptor;
PreviousEndpointDescriptor->NextPhysicalEndpoint = EndpointDescriptor->NextPhysicalEndpoint;
CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
//
// get corresponding request
// done
//
Request = PUSBREQUEST(EndpointDescriptor->Request);
//
// notify of completion
//
Request->CompletionCallback(EndpointDescriptor);
//
// FIXME: check if complete
//
ASSERT(Request->IsRequestComplete());
//
// release request
//
Request->Release();
return;
}
//
// find transfer descriptor in bulk list
//
Status = FindTransferDescriptorInEndpoint(m_BulkHeadEndpointDescriptor, TransferDescriptorLogicalAddress, &EndpointDescriptor, &PreviousEndpointDescriptor);
if (NT_SUCCESS(Status))
{
//
// cleanup endpoint
//
CleanupEndpointDescriptor(EndpointDescriptor, PreviousEndpointDescriptor);
//
// done
//
return;
}
//
// hardware reported dead endpoint completed
//
DPRINT1("CUSBQueue::TransferDescriptorCompletionCallback invalid transfer descriptor %x\n", TransferDescriptorLogicalAddress);
ASSERT(FALSE);
}

View file

@ -45,6 +45,7 @@ public:
virtual BOOLEAN IsRequestInitialized();
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
virtual VOID CompletionCallback(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
virtual VOID FreeEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor);
// local functions
ULONG InternalGetTransferType();
@ -53,6 +54,7 @@ public:
NTSTATUS BuildSetupPacket();
NTSTATUS BuildSetupPacketFromURB();
NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
NTSTATUS BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
NTSTATUS CreateGeneralTransferDescriptor(POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize);
VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor);
NTSTATUS AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor);
@ -606,10 +608,36 @@ CUSBRequest::AllocateEndpointDescriptor(
//
// append device address and endpoint number
//
Descriptor->Flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(m_DeviceAddress);
Descriptor->Flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(GetDeviceAddress());
Descriptor->Flags |= OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(GetEndpointAddress());
Descriptor->Flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(GetMaxPacketSize());
//
// is there an endpoint descriptor
//
if (m_EndpointDescriptor)
{
//
// check direction
//
if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->bEndpointAddress))
{
//
// direction out
//
Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_OUT;
}
else
{
//
// direction in
//
Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_IN;
}
}
//
// FIXME: detect type
//
@ -631,6 +659,198 @@ CUSBRequest::AllocateEndpointDescriptor(
return STATUS_SUCCESS;
}
NTSTATUS
CUSBRequest::BuildBulkInterruptEndpoint(
POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
{
POHCI_GENERAL_TD FirstDescriptor, PreviousDescriptor = NULL, CurrentDescriptor, LastDescriptor;
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
ULONG BufferSize, CurrentSize, Direction, MaxLengthInPage;
NTSTATUS Status;
PVOID Buffer;
//
// allocate endpoint descriptor
//
Status = AllocateEndpointDescriptor(&EndpointDescriptor);
if (!NT_SUCCESS(Status))
{
//
// failed to create setup descriptor
//
return Status;
}
//
// allocate transfer descriptor for last descriptor
//
Status = CreateGeneralTransferDescriptor(&LastDescriptor, 0);
if (!NT_SUCCESS(Status))
{
//
// failed to create transfer descriptor
//
m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
return Status;
}
//
// get buffer size
//
BufferSize = m_TransferBufferLength;
ASSERT(BufferSize);
ASSERT(m_TransferBufferMDL);
//
// get buffer
//
Buffer = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
ASSERT(Buffer);
if (InternalGetPidDirection())
{
//
// input direction
//
Direction = OHCI_TD_DIRECTION_PID_IN;
}
else
{
//
// output direction
//
Direction = OHCI_TD_DIRECTION_PID_OUT;
}
do
{
//
// get current buffersize
//
CurrentSize = min(8192, BufferSize);
//
// get page offset
//
MaxLengthInPage = PAGE_SIZE - BYTE_OFFSET(Buffer);
//
// get minimum from current page size
//
CurrentSize = min(CurrentSize, MaxLengthInPage);
ASSERT(CurrentSize);
//
// allocate transfer descriptor
//
Status = CreateGeneralTransferDescriptor(&CurrentDescriptor, 0);
if (!NT_SUCCESS(Status))
{
//
// failed to create transfer descriptor
// TODO: cleanup
//
ASSERT(FALSE);
m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
FreeDescriptor(LastDescriptor);
return Status;
}
//
// initialize descriptor
//
CurrentDescriptor->Flags = Direction | 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;
//
// store physical address of buffer
//
CurrentDescriptor->BufferPhysical = MmGetPhysicalAddress(Buffer).LowPart;
CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + CurrentSize - 1;
//
// is there a previous descriptor
//
if (PreviousDescriptor)
{
//
// link descriptors
//
PreviousDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor;
PreviousDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
}
else
{
//
// it is the first descriptor
//
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);
//
// set previous descriptor
//
PreviousDescriptor = CurrentDescriptor;
//
// subtract buffer size
//
BufferSize -= CurrentSize;
//
// increment buffer offset
//
Buffer = (PVOID)((ULONG_PTR)Buffer + CurrentSize);
}while(BufferSize);
//
// first descriptor has no carry bit
//
FirstDescriptor->Flags &= ~OHCI_TD_TOGGLE_CARRY;
//
// fixme: toggle
//
FirstDescriptor->Flags |= OHCI_TD_TOGGLE_0;
//
// clear interrupt mask for last transfer descriptor
//
CurrentDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK;
//
// fire interrupt as soon transfer is finished
//
CurrentDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
//
// link last data descriptor to last descriptor
//
CurrentDescriptor->NextLogicalDescriptor = LastDescriptor;
CurrentDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
//
// now link descriptor to endpoint
//
EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart;
EndpointDescriptor->TailPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart;
EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor;
//
// store result
//
*OutEndpointDescriptor = EndpointDescriptor;
//
// done
//
return STATUS_SUCCESS;
}
NTSTATUS
CUSBRequest::BuildControlTransferDescriptor(
POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
@ -639,8 +859,6 @@ CUSBRequest::BuildControlTransferDescriptor(
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
NTSTATUS Status;
DPRINT1("CUSBRequest::BuildControlTransferDescriptor\n");
//
// allocate endpoint descriptor
//
@ -695,7 +913,6 @@ CUSBRequest::BuildControlTransferDescriptor(
return Status;
}
if (m_TransferBufferLength)
{
//
@ -729,6 +946,7 @@ CUSBRequest::BuildControlTransferDescriptor(
//
DataDescriptor->BufferPhysical = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart;
DataDescriptor->LastPhysicalByteAddress = DataDescriptor->BufferPhysical + m_TransferBufferLength - 1;
}
//
@ -849,12 +1067,8 @@ CUSBRequest::GetEndpointDescriptor(
Status = BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
break;
case USB_ENDPOINT_TYPE_BULK:
DPRINT1("USB_ENDPOINT_TYPE_BULK not implemented\n");
Status = STATUS_NOT_IMPLEMENTED; //BuildBulkTransferQueueHead(OutDescriptor);
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
DPRINT1("USB_ENDPOINT_TYPE_INTERRUPT not implemented\n");
Status = STATUS_NOT_IMPLEMENTED;
Status = BuildBulkInterruptEndpoint(OutDescriptor);
break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n");
@ -919,32 +1133,24 @@ CUSBRequest::GetResultStatus(
}
VOID
CUSBRequest::CompletionCallback(
CUSBRequest::FreeEndpointDescriptor(
struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
{
POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
DPRINT1("CUSBRequest::CompletionCallback\n");
//
// set status code
//
m_NtStatusCode = STATUS_SUCCESS;
m_UrbStatusCode = USBD_STATUS_SUCCESS;
ASSERT(!m_Irp);
//
// FIXME: cleanup descriptors
//
DPRINT("CUSBRequest::FreeEndpointDescriptor EndpointDescriptor %p Logical %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
//
// get first general transfer descriptor
//
TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
//
// release endpoint descriptor
//
m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
while(TransferDescriptor)
{
//
@ -963,6 +1169,8 @@ CUSBRequest::CompletionCallback(
m_DmaManager->Release(TransferDescriptor->BufferLogical, TransferDescriptor->BufferSize);
}
DPRINT("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x\n", TransferDescriptor, TransferDescriptor->PhysicalAddress.LowPart, TransferDescriptor->BufferPhysical, TransferDescriptor->LastPhysicalByteAddress);
//
// release descriptor
//
@ -974,16 +1182,75 @@ CUSBRequest::CompletionCallback(
TransferDescriptor = NextTransferDescriptor;
}
//
// release endpoint descriptor
//
m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
}
VOID
CUSBRequest::CompletionCallback(
struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
{
POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
PIO_STACK_LOCATION IoStack;
PURB Urb;
DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
//
// signal completion event
// set status code
//
PC_ASSERT(m_CompletionEvent);
KeSetEvent(m_CompletionEvent, 0, FALSE);
m_NtStatusCode = STATUS_SUCCESS;
m_UrbStatusCode = USBD_STATUS_SUCCESS;
if (m_Irp)
{
//
// set irp completion status
//
m_Irp->IoStatus.Status = STATUS_SUCCESS; //FIXME
//
// 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_SUCCESS; //FIXME
//
// Check if the MDL was created
//
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{
//
// Free Mdl
//
IoFreeMdl(m_TransferBufferMDL);
}
//
// FIXME: support status and calculate length
//
//
// FIXME: check if the transfer was split
// if yes dont complete irp yet
//
IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
}
else
{
//
// signal completion event
//
PC_ASSERT(m_CompletionEvent);
KeSetEvent(m_CompletionEvent, 0, FALSE);
}
}