[USBOHCI]

- Implement function to retrieve isochronous head endpoint descriptor
- Implement function to retrieve current frame number
- Set isochronous descriptor flag for head endpoint
- Implement retrieve device status for devices
- Implement retrieve class status from device
- Partly implement isochronous descriptor handling in usb queue
- Start implementing isochronous transfers in ISUBRequest
- Code currently not tested as the Virtual Machine with XP + ReactOS usbohci driver brings down the host system when starting the iso transfers. Ironically it crashes in MS usbohci driver


svn path=/branches/usb-bringup/; revision=51957
This commit is contained in:
Johannes Anderwald 2011-05-27 13:04:55 +00:00
parent 9aff3e967c
commit 2231c8333a
6 changed files with 503 additions and 45 deletions

View file

@ -62,8 +62,10 @@ public:
NTSTATUS GetBulkHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor); NTSTATUS GetBulkHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor); NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
NTSTATUS GetInterruptEndpointDescriptors(struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor); NTSTATUS GetInterruptEndpointDescriptors(struct _OHCI_ENDPOINT_DESCRIPTOR *** OutDescriptor);
NTSTATUS GetIsochronousHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor);
VOID HeadEndpointDescriptorModified(ULONG HeadType); VOID HeadEndpointDescriptorModified(ULONG HeadType);
NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager); NTSTATUS GetDMA(OUT struct IDMAMemoryManager **m_DmaManager);
NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue); NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue);
@ -80,6 +82,7 @@ public:
KIRQL AcquireDeviceLock(void); KIRQL AcquireDeviceLock(void);
VOID ReleaseDeviceLock(KIRQL OldLevel); VOID ReleaseDeviceLock(KIRQL OldLevel);
virtual VOID GetCurrentFrameNumber(PULONG FrameNumber);
// local // local
BOOLEAN InterruptService(); BOOLEAN InterruptService();
NTSTATUS InitializeController(); NTSTATUS InitializeController();
@ -698,6 +701,17 @@ CUSBHardwareDevice::GetInterruptEndpointDescriptors(
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
NTSTATUS
CUSBHardwareDevice::GetIsochronousHeadEndpointDescriptor(
struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor)
{
//
// get descriptor
//
*OutDescriptor = m_IsoEndpointDescriptor;
return STATUS_SUCCESS;
}
VOID VOID
CUSBHardwareDevice::HeadEndpointDescriptorModified( CUSBHardwareDevice::HeadEndpointDescriptorModified(
ULONG Type) ULONG Type)
@ -848,6 +862,11 @@ CUSBHardwareDevice::InitializeController()
// //
m_InterruptEndpoints[0]->NextPhysicalEndpoint = m_IsoEndpointDescriptor->PhysicalAddress.LowPart; m_InterruptEndpoints[0]->NextPhysicalEndpoint = m_IsoEndpointDescriptor->PhysicalAddress.LowPart;
//
// set iso endpoint type
//
m_IsoEndpointDescriptor->Flags |= OHCI_ENDPOINT_ISOCHRONOUS_FORMAT;
// //
// done // done
// //
@ -1183,6 +1202,15 @@ CUSBHardwareDevice::AcquireDeviceLock(void)
return OldLevel; return OldLevel;
} }
VOID
CUSBHardwareDevice::GetCurrentFrameNumber(
PULONG FrameNumber)
{
//
// store frame number
//
*FrameNumber = m_HCCA->CurrentFrameNumber;
}
VOID VOID
CUSBHardwareDevice::ReleaseDeviceLock( CUSBHardwareDevice::ReleaseDeviceLock(

View file

@ -231,6 +231,8 @@ typedef struct _OHCI_ENDPOINT_DESCRIPTOR
#define OHCI_ENDPOINT_FULL_SPEED 0x00000000 #define OHCI_ENDPOINT_FULL_SPEED 0x00000000
#define OHCI_ENDPOINT_DIRECTION_OUT 0x00000800 #define OHCI_ENDPOINT_DIRECTION_OUT 0x00000800
#define OHCI_ENDPOINT_DIRECTION_IN 0x00001000 #define OHCI_ENDPOINT_DIRECTION_IN 0x00001000
#define OHCI_ENDPOINT_GENERAL_FORMAT 0x00000000
#define OHCI_ENDPOINT_ISOCHRONOUS_FORMAT 0x00008000
// //
// Maximum port count set by OHCI // Maximum port count set by OHCI
@ -293,3 +295,35 @@ typedef struct
#define OHCI_TD_CONDITION_BUFFER_OVERRUN 0x0c #define OHCI_TD_CONDITION_BUFFER_OVERRUN 0x0c
#define OHCI_TD_CONDITION_BUFFER_UNDERRUN 0x0d #define OHCI_TD_CONDITION_BUFFER_UNDERRUN 0x0d
#define OHCI_TD_CONDITION_NOT_ACCESSED 0x0f #define OHCI_TD_CONDITION_NOT_ACCESSED 0x0f
// --------------------------------
// Isochronous transfer descriptor structure (section 4.3.2)
// --------------------------------
#define OHCI_ITD_NOFFSET 8
typedef struct _OHCI_ISO_TD_
{
// Hardware part 32 byte
ULONG Flags;
ULONG BufferPhysical; // Physical page number of byte 0
ULONG NextPhysicalDescriptor; // Next isochronous transfer descriptor
ULONG LastPhysicalByteAddress; // Physical buffer end
ULONG Offset[OHCI_ITD_NOFFSET]; // Buffer offsets
// Software part
PHYSICAL_ADDRESS PhysicalAddress; // Physical address of this descriptor
struct _OHCI_ISO_TD_ * NextLogicalDescriptor; // Logical pointer next descriptor
}OHCI_ISO_TD, *POHCI_ISO_TD;
#define OHCI_ITD_GET_STARTING_FRAME(x) ((x) & 0x0000ffff)
#define OHCI_ITD_SET_STARTING_FRAME(x) ((x) & 0xffff)
#define OHCI_ITD_GET_DELAY_INTERRUPT(x) (((x) >> 21) & 7)
#define OHCI_ITD_SET_DELAY_INTERRUPT(x) ((x) << 21)
#define OHCI_ITD_NO_INTERRUPT 0x00e00000
#define OHCI_ITD_GET_FRAME_COUNT(x) ((((x) >> 24) & 7) + 1)
#define OHCI_ITD_SET_FRAME_COUNT(x) (((x) - 1) << 24)
#define OHCI_ITD_GET_CONDITION_CODE(x) ((x) >> 28)
#define OHCI_ITD_NO_CONDITION_CODE 0xf0000000

View file

@ -1119,7 +1119,10 @@ CHubController::HandleGetStatusFromDevice(
IN OUT PIRP Irp, IN OUT PIRP Irp,
PURB Urb) PURB Urb)
{ {
PUSHORT Status; PUSHORT DeviceStatus;
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
NTSTATUS Status;
PUSBDEVICE UsbDevice;
// //
// sanity checks // sanity checks
@ -1127,22 +1130,54 @@ CHubController::HandleGetStatusFromDevice(
PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); PC_ASSERT(Urb->UrbControlGetStatusRequest.Index == 0);
PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT)); PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBufferLength >= sizeof(USHORT));
PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer); PC_ASSERT(Urb->UrbControlGetStatusRequest.TransferBuffer);
PC_ASSERT(Urb->UrbHeader.UsbdDeviceHandle == NULL);
// //
// get status buffer // get status buffer
// //
Status = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer; DeviceStatus = (PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer;
if (Urb->UrbHeader.UsbdDeviceHandle == NULL)
{
//
// FIXME need more flags ?
//
*DeviceStatus = USB_PORT_STATUS_CONNECT;
return STATUS_SUCCESS;
}
// //
// FIXME need more flags ? // check if this is a valid usb device handle
// //
*Status = USB_PORT_STATUS_CONNECT; ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)));
//
// get device
//
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
//
// generate setup packet
//
CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
CtrlSetup.wValue.LowByte = 0;
CtrlSetup.wValue.HiByte = 0;
CtrlSetup.wIndex.W = Urb->UrbControlGetStatusRequest.Index;
CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
CtrlSetup.bmRequestType.B = 0x80;
//
// submit setup packet
//
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
ASSERT(Status == STATUS_SUCCESS);
DPRINT1("CHubController::HandleGetStatusFromDevice Status %x Length %lu DeviceStatus %x\n", Status, Urb->UrbControlDescriptorRequest.TransferBufferLength, *DeviceStatus);
// //
// done // done
// //
return STATUS_SUCCESS; return Status;
} }
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------
@ -1155,6 +1190,8 @@ CHubController::HandleClassDevice(
PUSB_HUB_DESCRIPTOR UsbHubDescriptor; PUSB_HUB_DESCRIPTOR UsbHubDescriptor;
ULONG PortCount, Dummy2; ULONG PortCount, Dummy2;
USHORT Dummy1; USHORT Dummy1;
PUSBDEVICE UsbDevice;
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
DPRINT("CHubController::HandleClassDevice Request %x Class %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value >> 8); DPRINT("CHubController::HandleClassDevice Request %x Class %x\n", Urb->UrbControlVendorClassRequest.Request, Urb->UrbControlVendorClassRequest.Value >> 8);
@ -1163,6 +1200,36 @@ CHubController::HandleClassDevice(
// //
switch(Urb->UrbControlVendorClassRequest.Request) switch(Urb->UrbControlVendorClassRequest.Request)
{ {
case USB_REQUEST_GET_STATUS:
{
//
// check if this is a valid usb device handle
//
ASSERT(ValidateUsbDevice(PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle)));
//
// get device
//
UsbDevice = PUSBDEVICE(Urb->UrbHeader.UsbdDeviceHandle);
//
// generate setup packet
//
CtrlSetup.bRequest = USB_REQUEST_GET_STATUS;
CtrlSetup.wValue.LowByte = Urb->UrbControlVendorClassRequest.Index;
CtrlSetup.wValue.W = Urb->UrbControlVendorClassRequest.Value;
CtrlSetup.wIndex.W = Urb->UrbControlVendorClassRequest.Index;
CtrlSetup.wLength = (USHORT)Urb->UrbControlGetStatusRequest.TransferBufferLength;
CtrlSetup.bmRequestType.B = 0xA0;
//
// submit setup packet
//
Status = UsbDevice->SubmitSetupPacket(&CtrlSetup, Urb->UrbControlDescriptorRequest.TransferBufferLength, Urb->UrbControlDescriptorRequest.TransferBuffer);
ASSERT(Status == STATUS_SUCCESS);
break;
}
case USB_REQUEST_GET_DESCRIPTOR: case USB_REQUEST_GET_DESCRIPTOR:
{ {
switch (Urb->UrbControlVendorClassRequest.Value >> 8) switch (Urb->UrbControlVendorClassRequest.Value >> 8)

View file

@ -188,6 +188,15 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
virtual NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0; virtual NTSTATUS GetControlHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0;
//-----------------------------------------------------------------------------------------
//
// GetIsochronousHeadEndpointDescriptor
//
// Description: returns the control head endpoint descriptor
virtual NTSTATUS GetIsochronousHeadEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) = 0;
//----------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------
// //
// GetInterruptEndpointDescriptors // GetInterruptEndpointDescriptors
@ -301,6 +310,14 @@ DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
// Description: releases the device lock // Description: releases the device lock
virtual void ReleaseDeviceLock(KIRQL OldLevel) = 0; virtual void ReleaseDeviceLock(KIRQL OldLevel) = 0;
//----------------------------------------------------------------------------------------
//
// GetCurrentFrameNumber
//
// Description: returns the current frame number
virtual VOID GetCurrentFrameNumber(PULONG FrameNumber) = 0;
}; };
typedef IUSBHardwareDevice *PUSBHARDWAREDEVICE; typedef IUSBHardwareDevice *PUSBHARDWAREDEVICE;

View file

@ -61,6 +61,7 @@ protected:
PUSBHARDWAREDEVICE m_Hardware; // hardware PUSBHARDWAREDEVICE m_Hardware; // hardware
POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor POHCI_ENDPOINT_DESCRIPTOR m_BulkHeadEndpointDescriptor; // bulk head descriptor
POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor POHCI_ENDPOINT_DESCRIPTOR m_ControlHeadEndpointDescriptor; // control head descriptor
POHCI_ENDPOINT_DESCRIPTOR m_IsoHeadEndpointDescriptor; // isochronous head descriptor
POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints; POHCI_ENDPOINT_DESCRIPTOR * m_InterruptEndpoints;
}; };
@ -100,6 +101,9 @@ CUSBQueue::Initialize(
// //
Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor); Hardware->GetControlHeadEndpointDescriptor(&m_ControlHeadEndpointDescriptor);
//
Hardware->GetIsochronousHeadEndpointDescriptor(&m_IsoHeadEndpointDescriptor);
// //
// get interrupt endpoints // get interrupt endpoints
// //
@ -164,6 +168,8 @@ CUSBQueue::AddUSBRequest(
KIRQL OldLevel; KIRQL OldLevel;
POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor; POHCI_ENDPOINT_DESCRIPTOR HeadDescriptor;
POHCI_ENDPOINT_DESCRIPTOR Descriptor; POHCI_ENDPOINT_DESCRIPTOR Descriptor;
POHCI_ISO_TD CurrentDescriptor;
ULONG FrameNumber;
DPRINT("CUSBQueue::AddUSBRequest\n"); DPRINT("CUSBQueue::AddUSBRequest\n");
@ -177,39 +183,6 @@ CUSBQueue::AddUSBRequest(
// //
Type = Request->GetTransferType(); Type = Request->GetTransferType();
//
// check if supported
//
switch(Type)
{
case USB_ENDPOINT_TYPE_ISOCHRONOUS:
/* NOT IMPLEMENTED IN QUEUE */
Status = STATUS_NOT_SUPPORTED;
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
case USB_ENDPOINT_TYPE_CONTROL:
case USB_ENDPOINT_TYPE_BULK:
Status = STATUS_SUCCESS;
break;
default:
/* BUG */
PC_ASSERT(FALSE);
Status = STATUS_NOT_SUPPORTED;
}
//
// check for success
//
if (!NT_SUCCESS(Status))
{
//
// request not supported, please try later
//
DPRINT1("Request Type %x not supported\n", Type);
ASSERT(FALSE);
return Status;
}
// //
// add extra reference which is released when the request is completed // add extra reference which is released when the request is completed
// //
@ -258,6 +231,48 @@ CUSBQueue::AddUSBRequest(
HeadDescriptor = FindInterruptEndpointDescriptor(Request->GetInterval()); HeadDescriptor = FindInterruptEndpointDescriptor(Request->GetInterval());
ASSERT(HeadDescriptor); ASSERT(HeadDescriptor);
} }
else if (Type == USB_ENDPOINT_TYPE_ISOCHRONOUS)
{
//
// get head descriptor
//
HeadDescriptor = m_IsoHeadEndpointDescriptor;
//
// get current frame number
//
m_Hardware->GetCurrentFrameNumber(&FrameNumber);
//
// increment frame number
//
FrameNumber++;
//
// apply frame number to iso transfer descriptors
//
CurrentDescriptor = (POHCI_ISO_TD)Descriptor->HeadLogicalDescriptor;
DPRINT1("ISO: NextFrameNumber %x\n", FrameNumber);
while(CurrentDescriptor)
{
//
// set current frame number
//
CurrentDescriptor->Flags |= OHCI_ITD_SET_STARTING_FRAME(FrameNumber);
//
// move to next frame number
//
FrameNumber++;
//
// move to next descriptor
//
CurrentDescriptor = CurrentDescriptor->NextLogicalDescriptor;
}
}
// //
// insert endpoint at end // insert endpoint at end
@ -269,9 +284,6 @@ CUSBQueue::AddUSBRequest(
// //
Descriptor->Flags &= ~OHCI_ENDPOINT_SKIP; Descriptor->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);
if (Type == USB_ENDPOINT_TYPE_CONTROL || Type == USB_ENDPOINT_TYPE_BULK) if (Type == USB_ENDPOINT_TYPE_CONTROL || Type == USB_ENDPOINT_TYPE_BULK)
{ {
// //
@ -280,6 +292,7 @@ CUSBQueue::AddUSBRequest(
m_Hardware->HeadEndpointDescriptorModified(Type); m_Hardware->HeadEndpointDescriptorModified(Type);
} }
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -57,9 +57,11 @@ public:
NTSTATUS BuildSetupPacketFromURB(); NTSTATUS BuildSetupPacketFromURB();
NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor); NTSTATUS BuildControlTransferDescriptor(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
NTSTATUS BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor); NTSTATUS BuildBulkInterruptEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
NTSTATUS BuildIsochronousEndpoint(POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor);
NTSTATUS CreateGeneralTransferDescriptor(POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize); NTSTATUS CreateGeneralTransferDescriptor(POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize);
VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor); VOID FreeDescriptor(POHCI_GENERAL_TD Descriptor);
NTSTATUS AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor); NTSTATUS AllocateEndpointDescriptor(OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor);
NTSTATUS CreateIsochronousTransferDescriptor(OUT POHCI_ISO_TD *OutDescriptor, ULONG FrameCount);
UCHAR GetEndpointAddress(); UCHAR GetEndpointAddress();
USHORT GetMaxPacketSize(); USHORT GetMaxPacketSize();
@ -243,6 +245,81 @@ CUSBRequest::InitializeWithIrp(
// //
switch (Urb->UrbHeader.Function) switch (Urb->UrbHeader.Function)
{ {
case URB_FUNCTION_ISOCH_TRANSFER:
{
//
// there must be at least one packet
//
ASSERT(Urb->UrbIsochronousTransfer.NumberOfPackets);
//
// is there data to be transferred
//
if (Urb->UrbIsochronousTransfer.TransferBufferLength)
{
//
// Check if there is a MDL
//
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{
//
// sanity check
//
PC_ASSERT(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,
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 = Urb->UrbIsochronousTransfer.TransferBufferMDL;
}
}
//
// save buffer length
//
m_TransferBufferLength = Urb->UrbIsochronousTransfer.TransferBufferLength;
//
// Set Length Completed to 0
//
m_TransferBufferLengthCompleted = 0;
//
// get endpoint descriptor
//
m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbIsochronousTransfer.PipeHandle;
//
// completed initialization
//
break;
}
// //
// luckily those request have the same structure layout // luckily those request have the same structure layout
// //
@ -525,6 +602,230 @@ CUSBRequest::FreeDescriptor(
m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD)); 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, PreviousDescriptor = NULL, CurrentDescriptor;
POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor;
ULONG Index = 0, SubIndex, NumberOfPackets, PageOffset;
NTSTATUS Status;
PVOID Buffer;
PIO_STACK_LOCATION IoStack;
PURB Urb;
DPRINT1("cp\n");
//
// 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
//
return Status;
}
DPRINT1("cp\n");
//
// get buffer
//
Buffer = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority);
ASSERT(Buffer);
DPRINT1("cp\n");
while(Index < Urb->UrbIsochronousTransfer.NumberOfPackets)
{
//
// get number of packets remaining
//
NumberOfPackets = min(Urb->UrbIsochronousTransfer.NumberOfPackets - Index, OHCI_ITD_NOFFSET);
DPRINT1("cp Number Packets %lu\n", NumberOfPackets);
//
// allocate iso descriptor
//
Status = CreateIsochronousTransferDescriptor(&CurrentDescriptor, NumberOfPackets);
if (!NT_SUCCESS(Status))
{
//
// FIXME: cleanup
// failed to allocate descriptor
//
ASSERT(FALSE);
return Status;
}
DPRINT1("cp\n");
//
// initialize descriptor
//
CurrentDescriptor->BufferPhysical = (MmGetPhysicalAddress(Buffer).LowPart & ~ (PAGE_SIZE - 1));
//
// get page offset
//
PageOffset = BYTE_OFFSET(MmGetPhysicalAddress(Buffer).LowPart);
DPRINT1("cp\n");
for(SubIndex = 0; SubIndex < NumberOfPackets; SubIndex++)
{
//
// store buffer offset
//
CurrentDescriptor->Offset[SubIndex] = Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset + PageOffset;
}
//
// increment packet offset
//
Index += NumberOfPackets;
//
// check if this is the last descriptor
//
if (Index == Urb->UrbIsochronousTransfer.NumberOfPackets)
{
//
// end of transfer
//
CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + m_TransferBufferLength - 1;
}
else
{
//
// use start address of next packet - 1
//
CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + PageOffset + Urb->UrbIsochronousTransfer.IsoPacket[Index + 1].Offset - 1;
//
// move buffer to next address
//
Buffer = (PVOID)((ULONG_PTR)Buffer + Urb->UrbIsochronousTransfer.IsoPacket[Index + 1].Offset);
}
//
// 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("cp\n");
//
// 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;
DPRINT1("cp\n");
//
// store result
//
*OutEndpointDescriptor = EndpointDescriptor;
//
// done
//
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------
NTSTATUS NTSTATUS
CUSBRequest::CreateGeneralTransferDescriptor( CUSBRequest::CreateGeneralTransferDescriptor(
@ -1084,8 +1385,7 @@ CUSBRequest::GetEndpointDescriptor(
Status = BuildBulkInterruptEndpoint(OutDescriptor); Status = BuildBulkInterruptEndpoint(OutDescriptor);
break; break;
case USB_ENDPOINT_TYPE_ISOCHRONOUS: case USB_ENDPOINT_TYPE_ISOCHRONOUS:
DPRINT1("USB_ENDPOINT_TYPE_ISOCHRONOUS not implemented\n"); Status = BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor);
Status = STATUS_NOT_IMPLEMENTED;
break; break;
default: default:
PC_ASSERT(FALSE); PC_ASSERT(FALSE);
@ -1201,7 +1501,6 @@ VOID
CUSBRequest::CompletionCallback( CUSBRequest::CompletionCallback(
struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor) struct _OHCI_ENDPOINT_DESCRIPTOR * OutDescriptor)
{ {
POHCI_GENERAL_TD TransferDescriptor, NextTransferDescriptor;
PIO_STACK_LOCATION IoStack; PIO_STACK_LOCATION IoStack;
PURB Urb; PURB Urb;