}
// IUSBRequest interface functions
- virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
- virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp);
+ virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN USB_DEVICE_SPEED DeviceSpeed, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
+ virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp, IN USB_DEVICE_SPEED DeviceSpeed);
virtual BOOLEAN IsRequestComplete();
virtual ULONG GetTransferType();
virtual NTSTATUS GetEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutEndpointDescriptor);
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);
+ virtual UCHAR GetInterval();
+
// local functions
ULONG InternalGetTransferType();
NTSTATUS BuildSetupPacket();
NTSTATUS BuildSetupPacketFromURB();
NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
+ NTSTATUS BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
+ NTSTATUS BuildIsochronousEndpoint(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);
+ 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){}
NTSTATUS m_NtStatusCode;
ULONG m_UrbStatusCode;
+ //
+ // device speed
+ //
+ USB_DEVICE_SPEED m_DeviceSpeed;
+
+ //
+ // store urb
+ //
+ PURB m_Urb;
};
//----------------------------------------------------------------------------------------
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
IN UCHAR DeviceAddress,
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
+ IN USB_DEVICE_SPEED DeviceSpeed,
IN OUT ULONG TransferBufferLength,
IN OUT PMDL TransferBuffer)
{
m_DeviceAddress = DeviceAddress;
m_EndpointDescriptor = EndpointDescriptor;
m_TotalBytesTransferred = 0;
+ m_DeviceSpeed = DeviceSpeed;
//
// Set Length Completed to 0
NTSTATUS
CUSBRequest::InitializeWithIrp(
IN PDMAMEMORYMANAGER DmaManager,
- IN OUT PIRP Irp)
+ IN OUT PIRP Irp,
+ IN USB_DEVICE_SPEED DeviceSpeed)
{
PIO_STACK_LOCATION IoStack;
- PURB Urb;
//
// sanity checks
//
// get urb
//
- Urb = (PURB)IoStack->Parameters.Others.Argument1;
+ m_Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// store irp
//
m_Irp = Irp;
+ //
+ // store speed
+ //
+ m_DeviceSpeed = DeviceSpeed;
+
//
// check function type
//
- switch (Urb->UrbHeader.Function)
+ switch (m_Urb->UrbHeader.Function)
{
+ case URB_FUNCTION_ISOCH_TRANSFER:
+ {
+ //
+ // there must be at least one packet
+ //
+ ASSERT(m_Urb->UrbIsochronousTransfer.NumberOfPackets);
+
+ //
+ // is there data to be transferred
+ //
+ if (m_Urb->UrbIsochronousTransfer.TransferBufferLength)
+ {
+ //
+ // Check if there is a MDL
+ //
+ if (!m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
+ {
+ //
+ // sanity check
+ //
+ PC_ASSERT(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
+
+ //
+ // Create one using TransferBuffer
+ //
+ DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
+ m_TransferBufferMDL = IoAllocateMdl(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
+ m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
+ FALSE,
+ FALSE,
+ NULL);
+
+ if (!m_TransferBufferMDL)
+ {
+ //
+ // failed to allocate mdl
+ //
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ //
+ // build mdl for non paged pool
+ // FIXME: Does hub driver already do this when passing MDL?
+ //
+ MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
+ }
+ else
+ {
+ //
+ // use provided mdl
+ //
+ m_TransferBufferMDL = m_Urb->UrbIsochronousTransfer.TransferBufferMDL;
+ }
+ }
+
+ //
+ // save buffer length
+ //
+ m_TransferBufferLength = m_Urb->UrbIsochronousTransfer.TransferBufferLength;
+
+ //
+ // Set Length Completed to 0
+ //
+ m_TransferBufferLengthCompleted = 0;
+
+ //
+ // get endpoint descriptor
+ //
+ m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)m_Urb->UrbIsochronousTransfer.PipeHandle;
+
+ //
+ // completed initialization
+ //
+ break;
+ }
//
// luckily those request have the same structure layout
//
//
// bulk interrupt transfer
//
- if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
+ if (m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
{
//
// Check if there is a MDL
//
- if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
+ if (!m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{
//
// sanity check
//
- PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
+ PC_ASSERT(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
//
// Create one using TransferBuffer
//
- DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
- m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
- Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
+ DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer, m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
+ m_TransferBufferMDL = IoAllocateMdl(m_Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
+ m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
FALSE,
FALSE,
NULL);
}
else
{
- m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
+ m_TransferBufferMDL = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
}
//
// save buffer length
//
- m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+ m_TransferBufferLength = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
//
// Set Length Completed to 0
//
// get endpoint descriptor
//
- m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
+ m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)m_Urb->UrbBulkOrInterruptTransfer.PipeHandle;
}
break;
}
default:
- DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
+ DPRINT1("URB Function: not supported %x\n", m_Urb->UrbHeader.Function);
PC_ASSERT(FALSE);
}
return m_EndpointDescriptor->wMaxPacketSize;
}
+UCHAR
+CUSBRequest::GetInterval()
+{
+ ASSERT(m_EndpointDescriptor);
+ ASSERT((m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
+
+ //
+ // return interrupt interval
+ //
+ return m_EndpointDescriptor->bInterval;
+}
+
UCHAR
CUSBRequest::GetEndpointAddress()
{
m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD));
}
+
+//----------------------------------------------------------------------------------------
+NTSTATUS
+CUSBRequest::CreateIsochronousTransferDescriptor(
+ POHCI_ISO_TD* OutDescriptor,
+ ULONG FrameCount)
+{
+ POHCI_ISO_TD Descriptor;
+ PHYSICAL_ADDRESS DescriptorAddress;
+ NTSTATUS Status;
+
+ //
+ // allocate transfer descriptor
+ //
+ Status = m_DmaManager->Allocate(sizeof(OHCI_ISO_TD), (PVOID*)&Descriptor, &DescriptorAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // no memory
+ //
+ return Status;
+ }
+
+ //
+ // initialize descriptor, hardware part
+ //
+ Descriptor->Flags = OHCI_ITD_SET_FRAME_COUNT(FrameCount) | OHCI_ITD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_NONE);// | OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED);
+ Descriptor->BufferPhysical = 0;
+ Descriptor->NextPhysicalDescriptor = 0;
+ Descriptor->LastPhysicalByteAddress = 0;
+
+ //
+ // software part
+ //
+ Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
+ Descriptor->NextLogicalDescriptor = 0;
+
+ //
+ // store result
+ //
+ *OutDescriptor = Descriptor;
+
+ //
+ // done
+ //
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+CUSBRequest::BuildIsochronousEndpoint(
+ POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
+{
+ POHCI_ISO_TD FirstDescriptor = NULL, PreviousDescriptor = NULL, CurrentDescriptor = NULL;
+ POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
+ ULONG Index = 0, SubIndex, NumberOfPackets, PageOffset, Page;
+ NTSTATUS Status;
+ PVOID Buffer;
+ PIO_STACK_LOCATION IoStack;
+ PURB Urb;
+ PHYSICAL_ADDRESS Address;
+
+ //
+ // get current irp stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(m_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;
+ ASSERT(Urb);
+
+ //
+ // allocate endpoint descriptor
+ //
+ Status = AllocateEndpointDescriptor(&EndpointDescriptor);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // failed to create setup descriptor
+ //
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ //
+ // get buffer
+ //
+ Buffer = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
+ ASSERT(Buffer);
+
+ //
+ // FIXME: support requests which spans serveral pages
+ //
+ ASSERT(ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(m_TransferBufferMDL), MmGetMdlByteCount(m_TransferBufferMDL)) <= 2);
+
+ Status = m_DmaManager->Allocate(m_TransferBufferLength, &Buffer, &Address);
+ ASSERT(Status == STATUS_SUCCESS);
+
+
+ while(Index < Urb->UrbIsochronousTransfer.NumberOfPackets)
+ {
+ //
+ // get number of packets remaining
+ //
+ NumberOfPackets = min(Urb->UrbIsochronousTransfer.NumberOfPackets - Index, OHCI_ITD_NOFFSET);
+ //
+ // allocate iso descriptor
+ //
+ Status = CreateIsochronousTransferDescriptor(&CurrentDescriptor, NumberOfPackets);
+ if (!NT_SUCCESS(Status))
+ {
+ //
+ // FIXME: cleanup
+ // failed to allocate descriptor
+ //
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ //
+ // get physical page
+ //
+ Page = MmGetPhysicalAddress(Buffer).LowPart;
+
+ //
+ // get page offset
+ //
+ PageOffset = BYTE_OFFSET(Page);
+
+ //
+ // initialize descriptor
+ //
+ CurrentDescriptor->BufferPhysical = Page - PageOffset;
+
+ for(SubIndex = 0; SubIndex < NumberOfPackets; SubIndex++)
+ {
+ //
+ // store buffer offset
+ //
+ CurrentDescriptor->Offset[SubIndex] = Urb->UrbIsochronousTransfer.IsoPacket[Index+SubIndex].Offset + PageOffset;
+ DPRINT1("Index %lu PacketOffset %lu FinalOffset %lu\n", SubIndex+Index, Urb->UrbIsochronousTransfer.IsoPacket[Index+SubIndex].Offset, CurrentDescriptor->Offset[SubIndex]);
+ }
+
+ //
+ // increment packet offset
+ //
+ Index += NumberOfPackets;
+
+ //
+ // check if this is the last descriptor
+ //
+ if (Index == Urb->UrbIsochronousTransfer.NumberOfPackets)
+ {
+ //
+ // end of transfer
+ //
+ CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + PageOffset + m_TransferBufferLength - 1;
+ }
+ else
+ {
+ //
+ // use start address of next packet - 1
+ //
+ CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + PageOffset + Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset - 1;
+ }
+
+ //
+ // is there a previous descriptor
+ //
+ if (PreviousDescriptor)
+ {
+ //
+ // link descriptors
+ //
+ PreviousDescriptor->NextLogicalDescriptor = CurrentDescriptor;
+ PreviousDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
+ }
+ else
+ {
+ //
+ // first descriptor
+ //
+ FirstDescriptor = CurrentDescriptor;
+ }
+
+ //
+ // store as previous descriptor
+ //
+ PreviousDescriptor = CurrentDescriptor;
+ DPRINT1("Current Descriptor %p Logical %lx StartAddress %x EndAddress %x\n", CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, CurrentDescriptor->BufferPhysical, CurrentDescriptor->LastPhysicalByteAddress);
+
+ //
+ // fire interrupt as soon transfer is finished
+ //
+ CurrentDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE);
+ }
+
+ //
+ // 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);
+
+ //
+ // set isochronous type
+ //
+ EndpointDescriptor->Flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
+
+ //
+ // now link descriptor to endpoint
+ //
+ EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart;
+ EndpointDescriptor->TailPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart;
+ EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor;
+
+ //
+ // store result
+ //
+ *OutEndpointDescriptor = EndpointDescriptor;
+
+ //
+ // done
+ //
+ return STATUS_SUCCESS;
+}
+
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::CreateGeneralTransferDescriptor(
//
// 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());
- //
- // FIXME: detect type
- //
- Descriptor->Flags |= OHCI_ENDPOINT_FULL_SPEED;
-
- Descriptor->HeadPhysicalDescriptor = 0;
- Descriptor->NextPhysicalEndpoint = 0;
- Descriptor->TailPhysicalDescriptor = 0;
- Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
+ DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %x\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize());
//
- // store result
- //
- *OutDescriptor = Descriptor;
-
+ // is there an endpoint descriptor
//
- // done
+ 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;
+ }
+
+ }
+
+ //
+ // set type
+ //
+ if (m_DeviceSpeed == UsbFullSpeed)
+ {
+ //
+ // device is full speed
+ //
+ Descriptor->Flags |= OHCI_ENDPOINT_FULL_SPEED;
+ }
+ else if (m_DeviceSpeed == UsbLowSpeed)
+ {
+ //
+ // device is full speed
+ //
+ Descriptor->Flags |= OHCI_ENDPOINT_LOW_SPEED;
+ }
+ else
+ {
+ //
+ // error
+ //
+ ASSERT(FALSE);
+ }
+
+ Descriptor->HeadPhysicalDescriptor = 0;
+ Descriptor->NextPhysicalEndpoint = 0;
+ Descriptor->TailPhysicalDescriptor = 0;
+ Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart;
+
+ //
+ // store result
+ //
+ *OutDescriptor = Descriptor;
+
+ //
+ // done
//
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;
+
+#if 0
+ if (m_Urb != NULL)
+ {
+ if (m_Urb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_SHORT_TRANSFER_OK)
+ {
+ //
+ // indicate short packet support
+ //
+ CurrentDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
+ }
+ }
+#endif
+
+ //
+ // 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 Logical %x Buffer Logical %p Physical %x Last Physical %x CurrentSize %lu\n", PreviousDescriptor, CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, 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)
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
NTSTATUS Status;
- DPRINT1("CUSBRequest::BuildControlTransferDescriptor\n");
-
//
// allocate endpoint descriptor
//
return Status;
}
-
if (m_TransferBufferLength)
{
//
//
// 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;
+ }
+
+ //
+ // use short packets
+ //
+ DataDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING;
//
// store physical address of buffer
//
// 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)
{
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");
- Status = STATUS_NOT_IMPLEMENTED;
+ Status = BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
break;
default:
PC_ASSERT(FALSE);
}
-
VOID
-CUSBRequest::CompletionCallback(
+CUSBRequest::FreeEndpointDescriptor(
struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
{
POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
+ POHCI_ISO_TD IsoTransferDescriptor, IsoNextTransferDescriptor;
+ ULONG Index, PacketCount;
+
+ DPRINT("CUSBRequest::FreeEndpointDescriptor EndpointDescriptor %p Logical %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
+
+ if (OutDescriptor->Flags & OHCI_ENDPOINT_ISOCHRONOUS_FORMAT)
+ {
+ //
+ // get first iso transfer descriptor
+ //
+ IsoTransferDescriptor = (POHCI_ISO_TD)OutDescriptor->HeadLogicalDescriptor;
+
+ //
+ // release endpoint descriptor
+ //
+ m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
+
+ while(IsoTransferDescriptor)
+ {
+ //
+ // get next
+ //
+ IsoNextTransferDescriptor = IsoTransferDescriptor->NextLogicalDescriptor;
+
+ //
+ // get packet count
+ //
+ PacketCount = OHCI_ITD_GET_FRAME_COUNT(IsoTransferDescriptor->Flags);
+
+ DPRINT1("CUSBRequest::FreeEndpointDescriptor Descriptor %p Logical %x Buffer Physical %x EndAddress %x PacketCount %lu\n", IsoTransferDescriptor, IsoTransferDescriptor->PhysicalAddress.LowPart, IsoTransferDescriptor->BufferPhysical, IsoTransferDescriptor->LastPhysicalByteAddress, PacketCount);
+
+ for(Index = 0; Index < PacketCount; Index++)
+ {
+ DPRINT1("PSW Index %lu Value %x\n", Index, IsoTransferDescriptor->Offset[Index]);
+ }
+
+ //
+ // release descriptor
+ //
+ m_DmaManager->Release(IsoTransferDescriptor, sizeof(OHCI_ISO_TD));
+
+ //
+ // move to next
+ //
+ IsoTransferDescriptor = IsoNextTransferDescriptor;
+ }
+ }
+ else
+ {
+ //
+ // get first general transfer descriptor
+ //
+ TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
+
+ //
+ // release endpoint descriptor
+ //
+ m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
+
+ while(TransferDescriptor)
+ {
+ //
+ // get next
+ //
+ NextTransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
+
+ //
+ // is there a buffer associated
+ //
+ if (TransferDescriptor->BufferSize)
+ {
+ //
+ // release buffer
+ //
+ 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
+ //
+ m_DmaManager->Release(TransferDescriptor, sizeof(OHCI_GENERAL_TD));
+
+ //
+ // move to next
+ //
+ TransferDescriptor = NextTransferDescriptor;
+ }
+ }
+
+}
+
+VOID
+CUSBRequest::CheckError(
+ struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
+{
+ POHCI_GENERAL_TD TransferDescriptor;
+ ULONG ConditionCode;
+ PURB Urb;
+ PIO_STACK_LOCATION IoStack;
- DPRINT1("CUSBRequest::CompletionCallback\n");
//
// set status code
m_NtStatusCode = STATUS_SUCCESS;
m_UrbStatusCode = USBD_STATUS_SUCCESS;
- ASSERT(!m_Irp);
- //
- // FIXME: cleanup descriptors
- //
+ 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)
+{
+ PIO_STACK_LOCATION IoStack;
+ PURB Urb;
+
+ DPRINT("CUSBRequest::CompletionCallback Descriptor %p PhysicalAddress %x\n", OutDescriptor, OutDescriptor->PhysicalAddress.LowPart);
//
- // get first general transfer descriptor
+ // check for errors
//
- TransferDescriptor = (POHCI_GENERAL_TD)OutDescriptor->HeadLogicalDescriptor;
+ CheckError(OutDescriptor);
- while(TransferDescriptor)
+ if (m_Irp)
{
//
- // get next
+ // set irp completion status
+ //
+ m_Irp->IoStatus.Status = m_NtStatusCode;
+
+ //
+ // get current irp stack location
+ //
+ IoStack = IoGetCurrentIrpStackLocation(m_Irp);
+
+ //
+ // get urb
//
- NextTransferDescriptor = (POHCI_GENERAL_TD)TransferDescriptor->NextLogicalDescriptor;
+ Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
- // is there a buffer associated
+ // store urb status
//
- if (TransferDescriptor->BufferSize)
+ Urb->UrbHeader.Status = m_UrbStatusCode;
+
+ //
+ // Check if the MDL was created
+ //
+ if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{
//
- // release buffer
+ // Free Mdl
//
- m_DmaManager->Release(TransferDescriptor->BufferLogical, TransferDescriptor->BufferSize);
+ IoFreeMdl(m_TransferBufferMDL);
}
//
- // release descriptor
+ // FIXME: support status and calculate length
//
- m_DmaManager->Release(TransferDescriptor, sizeof(OHCI_GENERAL_TD));
//
- // move to next
+ // FIXME: check if the transfer was split
+ // if yes dont complete irp yet
//
- TransferDescriptor = NextTransferDescriptor;
+ IoCompleteRequest(m_Irp, IO_NO_INCREMENT);
+ }
+ else
+ {
+ //
+ // signal completion event
+ //
+ PC_ASSERT(m_CompletionEvent);
+ KeSetEvent(m_CompletionEvent, 0, FALSE);
}
-
- //
- // release endpoint descriptor
- //
- m_DmaManager->Release(OutDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR));
-
- //
- // signal completion event
- //
- PC_ASSERT(m_CompletionEvent);
- KeSetEvent(m_CompletionEvent, 0, FALSE);
}