/* * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/usb/usbohci/usb_request.cpp * PURPOSE: USB OHCI device driver. * PROGRAMMERS: * Michael Martin (michael.martin@reactos.org) * Johannes Anderwald (johannes.anderwald@reactos.org) */ #include "usbohci.h" #define NDEBUG #include class CUSBRequest : public IOHCIRequest { public: STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); STDMETHODIMP_(ULONG) AddRef() { InterlockedIncrement(&m_Ref); return m_Ref; } STDMETHODIMP_(ULONG) Release() { InterlockedDecrement(&m_Ref); if (!m_Ref) { delete this; return 0; } return m_Ref; } // IUSBRequest interface functions IMP_IUSBREQUEST IMP_IOHCIREQUEST // local functions ULONG InternalGetTransferType(); UCHAR InternalGetPidDirection(); UCHAR STDMETHODCALLTYPE GetDeviceAddress(); 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); VOID DumpEndpointDescriptor(struct _OHCI_ENDPOINT_DESCRIPTOR *Descriptor); NTSTATUS BuildTransferDescriptorChain(IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode, OUT POHCI_GENERAL_TD * OutFirstDescriptor, OUT POHCI_GENERAL_TD * OutLastDescriptor, OUT PULONG OutTransferBufferOffset); VOID InitDescriptor(IN POHCI_GENERAL_TD CurrentDescriptor, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidCode); // constructor / destructor CUSBRequest(IUnknown *OuterUnknown); virtual ~CUSBRequest(); protected: LONG m_Ref; // // memory manager for allocating setup packet / queue head / transfer descriptors // PDMAMEMORYMANAGER m_DmaManager; // // caller provided irp packet containing URB request // PIRP m_Irp; // // transfer buffer length // ULONG m_TransferBufferLength; // // current transfer length // ULONG m_TransferBufferLengthCompleted; // // Total Transfer Length // ULONG m_TotalBytesTransferred; // // transfer buffer MDL // PMDL m_TransferBufferMDL; // // caller provided setup packet // PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket; // // completion event for callers who initialized request with setup packet // PKEVENT m_CompletionEvent; // // device address for callers who initialized it with device address // UCHAR m_DeviceAddress; // // store endpoint descriptor // PUSB_ENDPOINT m_EndpointDescriptor; // // allocated setup packet from the DMA pool // PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket; PHYSICAL_ADDRESS m_DescriptorSetupPacket; // // stores the result of the operation // NTSTATUS m_NtStatusCode; ULONG m_UrbStatusCode; // // device speed // USB_DEVICE_SPEED m_DeviceSpeed; // // store urb // PURB m_Urb; // // base buffer // PVOID m_Base; }; //---------------------------------------------------------------------------------------- CUSBRequest::CUSBRequest(IUnknown *OuterUnknown) : m_CompletionEvent(NULL) { UNREFERENCED_PARAMETER(OuterUnknown); } //---------------------------------------------------------------------------------------- CUSBRequest::~CUSBRequest() { if (m_CompletionEvent != NULL) { ExFreePoolWithTag(m_CompletionEvent, TAG_USBOHCI); } } //---------------------------------------------------------------------------------------- NTSTATUS STDMETHODCALLTYPE CUSBRequest::QueryInterface( IN REFIID refiid, OUT PVOID* Output) { return STATUS_UNSUCCESSFUL; } //---------------------------------------------------------------------------------------- NTSTATUS STDMETHODCALLTYPE CUSBRequest::InitializeWithSetupPacket( IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN PUSBDEVICE Device, IN OPTIONAL struct _USB_ENDPOINT* EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer) { // // sanity checks // PC_ASSERT(DmaManager); PC_ASSERT(SetupPacket); // // initialize packet // m_DmaManager = DmaManager; m_SetupPacket = SetupPacket; m_TransferBufferLength = TransferBufferLength; m_TransferBufferMDL = TransferBuffer; m_DeviceAddress = Device->GetDeviceAddress(); m_EndpointDescriptor = EndpointDescriptor; m_TotalBytesTransferred = 0; m_DeviceSpeed = Device->GetSpeed(); // // Set Length Completed to 0 // m_TransferBufferLengthCompleted = 0; // // allocate completion event // m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBOHCI); if (!m_CompletionEvent) { // // failed to allocate completion event // return STATUS_INSUFFICIENT_RESOURCES; } // // initialize completion event // KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE); // // done // return STATUS_SUCCESS; } //---------------------------------------------------------------------------------------- NTSTATUS STDMETHODCALLTYPE CUSBRequest::InitializeWithIrp( IN PDMAMEMORYMANAGER DmaManager, IN struct IUSBDevice* Device, IN OUT PIRP Irp) { PIO_STACK_LOCATION IoStack; // // sanity checks // PC_ASSERT(DmaManager); PC_ASSERT(Irp); m_DmaManager = DmaManager; m_TotalBytesTransferred = 0; // // get current irp stack location // IoStack = IoGetCurrentIrpStackLocation(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 // m_Urb = (PURB)IoStack->Parameters.Others.Argument1; // // store irp // m_Irp = Irp; // // store speed // m_DeviceSpeed = Device->GetSpeed(); // // check function type // 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)m_Urb->UrbIsochronousTransfer.PipeHandle; // // completed initialization // break; } // // luckily those request have the same structure layout // case URB_FUNCTION_CLASS_INTERFACE: case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: { // // bulk interrupt transfer // if (m_Urb->UrbBulkOrInterruptTransfer.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); // // Keep that ehci created the MDL and needs to free it. // } else { m_TransferBufferMDL = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL; } // // save buffer length // m_TransferBufferLength = m_Urb->UrbBulkOrInterruptTransfer.TransferBufferLength; // // Set Length Completed to 0 // m_TransferBufferLengthCompleted = 0; // // get endpoint descriptor // m_EndpointDescriptor = (PUSB_ENDPOINT)m_Urb->UrbBulkOrInterruptTransfer.PipeHandle; } break; } default: DPRINT1("URB Function: not supported %x\n", m_Urb->UrbHeader.Function); PC_ASSERT(FALSE); } // // done // return STATUS_SUCCESS; } //---------------------------------------------------------------------------------------- BOOLEAN STDMETHODCALLTYPE CUSBRequest::IsRequestComplete() { // // FIXME: check if request was split // // // Check if the transfer was completed, only valid for Bulk Transfers // if ((m_TransferBufferLengthCompleted < m_TransferBufferLength) && (GetTransferType() == USB_ENDPOINT_TYPE_BULK)) { // // Transfer not completed // return FALSE; } return TRUE; } //---------------------------------------------------------------------------------------- ULONG STDMETHODCALLTYPE CUSBRequest::GetTransferType() { // // call internal implementation // return InternalGetTransferType(); } USHORT CUSBRequest::GetMaxPacketSize() { if (!m_EndpointDescriptor) { if (m_DeviceSpeed == UsbLowSpeed) { // // control pipes use 8 bytes packets // return 8; } else { // // must be full speed // ASSERT(m_DeviceSpeed == UsbFullSpeed); return 64; } } ASSERT(m_Irp); ASSERT(m_EndpointDescriptor); // // return max packet size // return m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize; } UCHAR STDMETHODCALLTYPE CUSBRequest::GetInterval() { ASSERT(m_EndpointDescriptor); ASSERT((m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT); // // return interrupt interval // return m_EndpointDescriptor->EndPointDescriptor.bInterval; } UCHAR CUSBRequest::GetEndpointAddress() { if (!m_EndpointDescriptor) { // // control request // return 0; } ASSERT(m_Irp); ASSERT(m_EndpointDescriptor); // // endpoint number is between 1-15 // return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0xF); } //---------------------------------------------------------------------------------------- ULONG CUSBRequest::InternalGetTransferType() { ULONG TransferType; // // check if an irp is provided // if (m_Irp) { ASSERT(m_EndpointDescriptor); // // end point is defined in the low byte of bmAttributes // TransferType = (m_EndpointDescriptor->EndPointDescriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK); } else { // // initialized with setup packet, must be a control transfer // TransferType = USB_ENDPOINT_TYPE_CONTROL; } // // done // return TransferType; } UCHAR CUSBRequest::InternalGetPidDirection() { if (m_EndpointDescriptor) { // // end point direction is highest bit in bEndpointAddress // return (m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7; } else { // // request arrives on the control pipe, extract direction from setup packet // ASSERT(m_SetupPacket); return (m_SetupPacket->bmRequestType.B >> 7); } } //---------------------------------------------------------------------------------------- UCHAR STDMETHODCALLTYPE CUSBRequest::GetDeviceAddress() { PIO_STACK_LOCATION IoStack; PURB Urb; PUSBDEVICE UsbDevice; // // check if there is an irp provided // if (!m_Irp) { // // used provided address // return m_DeviceAddress; } // // get current stack location // IoStack = IoGetCurrentIrpStackLocation(m_Irp); // // get contained urb // Urb = (PURB)IoStack->Parameters.Others.Argument1; // // check if there is a pipe handle provided // if (Urb->UrbHeader.UsbdDeviceHandle) { // // there is a device handle provided // UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle; // // return device address // return UsbDevice->GetDeviceAddress(); } // // no device handle provided, it is the host root bus // return 0; } VOID CUSBRequest::FreeDescriptor( POHCI_GENERAL_TD Descriptor) { if (Descriptor->BufferSize) { // // free buffer // m_DmaManager->Release(Descriptor->BufferLogical, Descriptor->BufferSize); } // // release descriptor // 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 several 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 (HACK) // *(volatile char *)Buffer; 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; DPRINT("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; DPRINT("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( POHCI_GENERAL_TD* OutDescriptor, ULONG BufferSize) { POHCI_GENERAL_TD Descriptor; PHYSICAL_ADDRESS DescriptorAddress; NTSTATUS Status; // // allocate transfer descriptor // Status = m_DmaManager->Allocate(sizeof(OHCI_GENERAL_TD), (PVOID*)&Descriptor, &DescriptorAddress); if (!NT_SUCCESS(Status)) { // // no memory // return Status; } // // initialize descriptor, hardware part // Descriptor->Flags = 0; Descriptor->BufferPhysical = 0; Descriptor->NextPhysicalDescriptor = 0; Descriptor->LastPhysicalByteAddress = 0; // // software part // Descriptor->PhysicalAddress.QuadPart = DescriptorAddress.QuadPart; Descriptor->BufferSize = BufferSize; if (BufferSize > 0) { // // allocate buffer from dma // Status = m_DmaManager->Allocate(BufferSize, &Descriptor->BufferLogical, &DescriptorAddress); if (!NT_SUCCESS(Status)) { // // no memory // m_DmaManager->Release(Descriptor, sizeof(OHCI_GENERAL_TD)); return Status; } // // set physical address of buffer // Descriptor->BufferPhysical = DescriptorAddress.LowPart; Descriptor->LastPhysicalByteAddress = Descriptor->BufferPhysical + BufferSize - 1; } // // store result // *OutDescriptor = Descriptor; // // done // return STATUS_SUCCESS; } NTSTATUS CUSBRequest::AllocateEndpointDescriptor( OUT POHCI_ENDPOINT_DESCRIPTOR *OutDescriptor) { POHCI_ENDPOINT_DESCRIPTOR Descriptor; PHYSICAL_ADDRESS DescriptorAddress; NTSTATUS Status; // // allocate descriptor // Status = m_DmaManager->Allocate(sizeof(OHCI_ENDPOINT_DESCRIPTOR), (PVOID*)&Descriptor, &DescriptorAddress); if (!NT_SUCCESS(Status)) { // // failed to allocate descriptor // return Status; } // // initialize descriptor // Descriptor->Flags = OHCI_ENDPOINT_SKIP; // // append device address and endpoint number // 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()); DPRINT("Flags %x DeviceAddress %x EndpointAddress %x PacketSize %lu\n", Descriptor->Flags, GetDeviceAddress(), GetEndpointAddress(), GetMaxPacketSize()); // // is there an endpoint descriptor // if (m_EndpointDescriptor) { // // check direction // if (USB_ENDPOINT_DIRECTION_OUT(m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress)) { // // direction out // Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_OUT; } else { // // direction in // Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_IN; } } else { // // get it from transfer descriptor // Descriptor->Flags |= OHCI_ENDPOINT_DIRECTION_DESCRIPTOR; } // // 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; } VOID CUSBRequest::InitDescriptor( IN POHCI_GENERAL_TD CurrentDescriptor, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidDirection) { ULONG Direction; if (PidDirection) { // // input direction // Direction = OHCI_TD_DIRECTION_PID_IN; } else { // // output direction // Direction = OHCI_TD_DIRECTION_PID_OUT; } // // 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(TransferBuffer).LowPart; CurrentDescriptor->LastPhysicalByteAddress = CurrentDescriptor->BufferPhysical + TransferBufferLength - 1; DPRINT("CurrentDescriptor %p Addr %x TransferBufferLength %lu\n", CurrentDescriptor, CurrentDescriptor->PhysicalAddress.LowPart, TransferBufferLength); } NTSTATUS CUSBRequest::BuildTransferDescriptorChain( IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN UCHAR PidDirection, OUT POHCI_GENERAL_TD * OutFirstDescriptor, OUT POHCI_GENERAL_TD * OutLastDescriptor, OUT PULONG OutTransferBufferOffset) { POHCI_GENERAL_TD FirstDescriptor = NULL, CurrentDescriptor, LastDescriptor = NULL; NTSTATUS Status; ULONG MaxLengthInPage, TransferBufferOffset = 0; ULONG MaxPacketSize = 0, TransferSize, CurrentSize; // // for now use one page as maximum size // MaxPacketSize = PAGE_SIZE; do { // // allocate transfer descriptor // Status = CreateGeneralTransferDescriptor(&CurrentDescriptor, 0); if (!NT_SUCCESS(Status)) { // // failed to allocate transfer descriptor // return STATUS_INSUFFICIENT_RESOURCES; } if (MaxPacketSize) { // // transfer size is minimum available buffer or endpoint size // TransferSize = min(TransferBufferLength - TransferBufferOffset, MaxPacketSize); } else { // // use available buffer // TransferSize = TransferBufferLength - TransferBufferOffset; } // // get page offset // MaxLengthInPage = PAGE_SIZE - BYTE_OFFSET(TransferBuffer); // // get minimum from current page size // CurrentSize = min(TransferSize, MaxLengthInPage); ASSERT(CurrentSize); // // now init the descriptor // InitDescriptor(CurrentDescriptor, (PVOID)((ULONG_PTR)TransferBuffer + TransferBufferOffset), CurrentSize, PidDirection); // // adjust offset // TransferBufferOffset += CurrentSize; // // is there a previous descriptor // if (LastDescriptor) { // // link descriptors // LastDescriptor->NextLogicalDescriptor = (PVOID)CurrentDescriptor; LastDescriptor->NextPhysicalDescriptor = CurrentDescriptor->PhysicalAddress.LowPart; } else { // // it is the first descriptor // FirstDescriptor = CurrentDescriptor; } if(TransferBufferLength == TransferBufferOffset) { // // end reached // break; } }while(TRUE); if (OutFirstDescriptor) { // // store first descriptor // *OutFirstDescriptor = FirstDescriptor; } if (OutLastDescriptor) { // // store last descriptor // *OutLastDescriptor = CurrentDescriptor; } if (OutTransferBufferOffset) { // // store offset // *OutTransferBufferOffset = TransferBufferOffset; } // // done // return STATUS_SUCCESS; } NTSTATUS CUSBRequest::BuildBulkInterruptEndpoint( POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor) { POHCI_GENERAL_TD FirstDescriptor, LastDescriptor; POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor; NTSTATUS Status; PVOID Base; ULONG ChainDescriptorLength; // // sanity check // ASSERT(m_EndpointDescriptor); // // allocate endpoint descriptor // Status = AllocateEndpointDescriptor(&EndpointDescriptor); if (!NT_SUCCESS(Status)) { // // failed to create setup descriptor // return Status; } ASSERT(m_TransferBufferMDL); if (m_Base == NULL) { // // get buffer // m_Base = MmGetSystemAddressForMdlSafe(m_TransferBufferMDL, NormalPagePriority); } // // Increase the size of last transfer, 0 in case this is the first // Base = (PVOID)((ULONG_PTR)m_Base + m_TransferBufferLengthCompleted); // // sanity checks // ASSERT(m_EndpointDescriptor); ASSERT(Base); // // use 2 * PAGE_SIZE at max for each new request // ULONG MaxTransferLength = min(1 * PAGE_SIZE, m_TransferBufferLength - m_TransferBufferLengthCompleted); DPRINT("m_TransferBufferLength %lu m_TransferBufferLengthCompleted %lu DataToggle %x\n", m_TransferBufferLength, m_TransferBufferLengthCompleted, m_EndpointDescriptor->DataToggle); // // build bulk transfer descriptor chain // Status = BuildTransferDescriptorChain(Base, MaxTransferLength, InternalGetPidDirection(), &FirstDescriptor, &LastDescriptor, &ChainDescriptorLength); if (!NT_SUCCESS(Status)) { // // failed to build transfer descriptor chain // m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); return Status; } // // move to next offset // m_TransferBufferLengthCompleted += ChainDescriptorLength; // // first descriptor has no carry bit // FirstDescriptor->Flags &= ~OHCI_TD_TOGGLE_CARRY; // // apply data toggle // FirstDescriptor->Flags |= (m_EndpointDescriptor->DataToggle ? OHCI_TD_TOGGLE_1 : OHCI_TD_TOGGLE_0); // // clear interrupt mask for last transfer descriptor // LastDescriptor->Flags &= ~OHCI_TD_INTERRUPT_MASK; // // fire interrupt as soon transfer is finished // LastDescriptor->Flags |= OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE); // // now link descriptor to endpoint // EndpointDescriptor->HeadPhysicalDescriptor = FirstDescriptor->PhysicalAddress.LowPart; EndpointDescriptor->TailPhysicalDescriptor = (FirstDescriptor == LastDescriptor ? 0 : LastDescriptor->PhysicalAddress.LowPart); EndpointDescriptor->HeadLogicalDescriptor = FirstDescriptor; // // dump descriptor list // //DumpEndpointDescriptor(EndpointDescriptor); // // store result // *OutEndpointDescriptor = EndpointDescriptor; // // done // return STATUS_SUCCESS; } VOID CUSBRequest::DumpEndpointDescriptor( POHCI_ENDPOINT_DESCRIPTOR Descriptor) { ULONG Count = 0; POHCI_GENERAL_TD GeneralDescriptor; DPRINT1("EndpointDescriptor %p Addr %x\n", Descriptor, Descriptor->PhysicalAddress.LowPart); DPRINT1("EndpointDescriptor HeadPhysicalDescriptor %x HeadLogicalDescriptor %p\n", Descriptor->HeadPhysicalDescriptor, Descriptor->HeadLogicalDescriptor); DPRINT1("EndpointDescriptor TailPhysicalDescriptor %x\n", Descriptor->TailPhysicalDescriptor); DPRINT1("EndpointDescriptor NextDescriptor %p\n", Descriptor->NextDescriptor); DPRINT1("EndpointDescriptor NextPhysicalEndpoint %x\n", Descriptor->NextPhysicalEndpoint); DPRINT1("EndpointDescriptor Flags %x\n", Descriptor->Flags); GeneralDescriptor = (POHCI_GENERAL_TD)Descriptor->HeadLogicalDescriptor; while(GeneralDescriptor) { DPRINT1("Descriptor %lu Address %p Addr %x\n", Count, GeneralDescriptor, GeneralDescriptor->PhysicalAddress); DPRINT1("Descriptor %lu BufferLogical %p BufferPhysical %x\n", Count, GeneralDescriptor->BufferLogical, GeneralDescriptor->BufferPhysical); DPRINT1("Descriptor %lu BufferSize %lu\n", Count, GeneralDescriptor->BufferSize); DPRINT1("Descriptor %lu LastPhysicalByteAddress %x\n", Count, GeneralDescriptor->LastPhysicalByteAddress); DPRINT1("Descriptor %lu Flags %x\n", Count, GeneralDescriptor->Flags); DPRINT1("Descriptor %lu NextLogicalDescriptor %p NextPhysicalDescriptor %x\n", Count, GeneralDescriptor->NextLogicalDescriptor, GeneralDescriptor->NextPhysicalDescriptor); Count++; GeneralDescriptor = (POHCI_GENERAL_TD)GeneralDescriptor->NextLogicalDescriptor; } } NTSTATUS CUSBRequest::BuildControlTransferDescriptor( POHCI_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor) { POHCI_GENERAL_TD SetupDescriptor, StatusDescriptor, DataDescriptor = NULL, LastDescriptor; POHCI_ENDPOINT_DESCRIPTOR EndpointDescriptor; NTSTATUS Status; // // allocate endpoint descriptor // Status = AllocateEndpointDescriptor(&EndpointDescriptor); if (!NT_SUCCESS(Status)) { // // failed to create setup descriptor // return Status; } // // first allocate setup descriptor // Status = CreateGeneralTransferDescriptor(&SetupDescriptor, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); if (!NT_SUCCESS(Status)) { // // failed to create setup descriptor // m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); return Status; } // // now create the status descriptor // Status = CreateGeneralTransferDescriptor(&StatusDescriptor, 0); if (!NT_SUCCESS(Status)) { // // failed to create status descriptor // FreeDescriptor(SetupDescriptor); m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); return Status; } // // finally create the last descriptor // Status = CreateGeneralTransferDescriptor(&LastDescriptor, 0); if (!NT_SUCCESS(Status)) { // // failed to create status descriptor // FreeDescriptor(SetupDescriptor); FreeDescriptor(StatusDescriptor); m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); return Status; } // // initialize setup descriptor // 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); // // initialize status descriptor // StatusDescriptor->Flags = OHCI_TD_SET_CONDITION_CODE(OHCI_TD_CONDITION_NOT_ACCESSED) | OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DELAY_INTERRUPT(OHCI_TD_INTERRUPT_IMMEDIATE); if (m_SetupPacket) { // // copy setup packet // RtlCopyMemory(SetupDescriptor->BufferLogical, m_SetupPacket, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); } else { // // generate setup packet from urb // ASSERT(FALSE); } if (m_TransferBufferLength) { // // FIXME: support more than one data descriptor // ASSERT(m_TransferBufferLength < 8192); // // now create the data descriptor // Status = CreateGeneralTransferDescriptor(&DataDescriptor, 0); if (!NT_SUCCESS(Status)) { // // failed to create status descriptor // m_DmaManager->Release(EndpointDescriptor, sizeof(OHCI_ENDPOINT_DESCRIPTOR)); FreeDescriptor(SetupDescriptor); FreeDescriptor(StatusDescriptor); return Status; } // // initialize data descriptor // 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; // // setup pid direction // DataDescriptor->Flags |= (InternalGetPidDirection() != FALSE) ? OHCI_TD_DIRECTION_PID_IN : OHCI_TD_DIRECTION_PID_OUT; // // use short packets // DataDescriptor->Flags |= OHCI_TD_BUFFER_ROUNDING; // // store physical address of buffer // DataDescriptor->BufferPhysical = MmGetPhysicalAddress(MmGetMdlVirtualAddress(m_TransferBufferMDL)).LowPart; DataDescriptor->LastPhysicalByteAddress = DataDescriptor->BufferPhysical + m_TransferBufferLength - 1; // // flip status pid direction // StatusDescriptor->Flags |= (InternalGetPidDirection() != FALSE) ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN; // // link setup descriptor to data descriptor // SetupDescriptor->NextPhysicalDescriptor = DataDescriptor->PhysicalAddress.LowPart; SetupDescriptor->NextLogicalDescriptor = DataDescriptor; // // link data descriptor to status descriptor // FIXME: check if there are more data descriptors // DataDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart; DataDescriptor->NextLogicalDescriptor = StatusDescriptor; // // link status descriptor to last descriptor // StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart; StatusDescriptor->NextLogicalDescriptor = LastDescriptor; } else { // // status descriptor is always in // StatusDescriptor->Flags |= OHCI_TD_DIRECTION_PID_IN; // // link setup descriptor to status descriptor // SetupDescriptor->NextPhysicalDescriptor = StatusDescriptor->PhysicalAddress.LowPart; SetupDescriptor->NextLogicalDescriptor = StatusDescriptor; // // link status descriptor to last descriptor // StatusDescriptor->NextPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart; StatusDescriptor->NextLogicalDescriptor = LastDescriptor; } // // now link descriptor to endpoint // EndpointDescriptor->HeadPhysicalDescriptor = SetupDescriptor->PhysicalAddress.LowPart; EndpointDescriptor->TailPhysicalDescriptor = LastDescriptor->PhysicalAddress.LowPart; EndpointDescriptor->HeadLogicalDescriptor = SetupDescriptor; // // store result // *OutEndpointDescriptor = EndpointDescriptor; // // dump descriptor // //DumpEndpointDescriptor(EndpointDescriptor); // // done // return STATUS_SUCCESS; } //---------------------------------------------------------------------------------------- NTSTATUS STDMETHODCALLTYPE CUSBRequest::GetEndpointDescriptor( struct _OHCI_ENDPOINT_DESCRIPTOR ** OutDescriptor) { ULONG TransferType; NTSTATUS Status; // // get transfer type // TransferType = InternalGetTransferType(); // // build request depending on type // switch(TransferType) { case USB_ENDPOINT_TYPE_CONTROL: Status = BuildControlTransferDescriptor((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor); break; case USB_ENDPOINT_TYPE_BULK: case USB_ENDPOINT_TYPE_INTERRUPT: Status = BuildBulkInterruptEndpoint(OutDescriptor); break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: Status = BuildIsochronousEndpoint((POHCI_ENDPOINT_DESCRIPTOR*)OutDescriptor); break; default: PC_ASSERT(FALSE); Status = STATUS_NOT_IMPLEMENTED; break; } if (NT_SUCCESS(Status)) { // // store queue head // //m_QueueHead = *OutDescriptor; // // store request object // (*OutDescriptor)->Request = PVOID(this); } // // done // return Status; } //---------------------------------------------------------------------------------------- VOID STDMETHODCALLTYPE CUSBRequest::GetResultStatus( OUT OPTIONAL NTSTATUS * NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode) { // // sanity check // PC_ASSERT(m_CompletionEvent); // // wait for the operation to complete // KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL); // // copy status // if (NtStatusCode) { *NtStatusCode = m_NtStatusCode; } // // copy urb status // if (UrbStatusCode) { *UrbStatusCode = m_UrbStatusCode; } } VOID STDMETHODCALLTYPE 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); // // check for errors // CheckError(OutDescriptor); 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); DPRINT("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++) { DPRINT("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; // // 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; if (m_EndpointDescriptor != NULL) { // // update data toggle // m_EndpointDescriptor->DataToggle = (OutDescriptor->HeadPhysicalDescriptor & OHCI_ENDPOINT_TOGGLE_CARRY); } while(TransferDescriptor) { // // 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 STDMETHODCALLTYPE CUSBRequest::CompletionCallback() { PIO_STACK_LOCATION IoStack; PURB Urb; DPRINT("CUSBRequest::CompletionCallback\n"); if (m_Irp) { // // set irp completion status // m_Irp->IoStatus.Status = m_NtStatusCode; // // get current irp stack location // IoStack = IoGetCurrentIrpStackLocation(m_Irp); // // get urb // Urb = (PURB)IoStack->Parameters.Others.Argument1; // // store urb status // Urb->UrbHeader.Status = m_UrbStatusCode; // // Check if the MDL was created // if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL) { // // Free Mdl // IoFreeMdl(m_TransferBufferMDL); } // // FIXME calculate length // // // complete request // IoCompleteRequest(m_Irp, IO_NO_INCREMENT); } else { // // signal completion event // PC_ASSERT(m_CompletionEvent); KeSetEvent(m_CompletionEvent, 0, FALSE); } } //----------------------------------------------------------------------------------------- NTSTATUS NTAPI InternalCreateUSBRequest( PUSBREQUEST *OutRequest) { PUSBREQUEST This; // // allocate requests // This = new(NonPagedPool, TAG_USBOHCI) CUSBRequest(0); if (!This) { // // failed to allocate // return STATUS_INSUFFICIENT_RESOURCES; } // // add reference count // This->AddRef(); // // return result // *OutRequest = (PUSBREQUEST)This; // // done // return STATUS_SUCCESS; }