Author: mjmartin Date: Fri Dec 31 12:01:21 2010 New Revision: 50230
URL: http://svn.reactos.org/svn/reactos?rev=50230&view=rev Log: [usb/usbehci]: - Implement creating and deleting Queue Heads and Transfer Descriptors from common buffer. - Implement linking/unlinking QueueHeads to create a linked list for Asynchronous Schedule traversal. - Implement BuildSetupPacketFromURB for creating a setup packet from a URB. - Implement SubmitControlTransfer.
Added: trunk/reactos/drivers/usb/usbehci/hwiface.c (with props) trunk/reactos/drivers/usb/usbehci/hwiface.h (with props) trunk/reactos/drivers/usb/usbehci/transfer.c (with props) trunk/reactos/drivers/usb/usbehci/transfer.h (with props)
Added: trunk/reactos/drivers/usb/usbehci/hwiface.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbehci/hwiface... ============================================================================== --- trunk/reactos/drivers/usb/usbehci/hwiface.c (added) +++ trunk/reactos/drivers/usb/usbehci/hwiface.c [iso-8859-1] Fri Dec 31 12:01:21 2010 @@ -1,0 +1,175 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbehci/hwiface.c + * PURPOSE: EHCI Interface routines: Queue Heads and Queue Element + Transfer Descriptors. + * TODO: Periodic Frame List, Isochronous Transaction Descriptors + and Split-transaction ITD. + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + */ + +#include "hwiface.h" +#include "physmem.h" +#define NDEBUG +#include <debug.h> + +/* Queue Element Transfer Descriptors */ + +PQUEUE_TRANSFER_DESCRIPTOR +CreateDescriptor(PEHCI_HOST_CONTROLLER hcd, UCHAR PIDCode, ULONG TotalBytesToTransfer) +{ + PQUEUE_TRANSFER_DESCRIPTOR Descriptor; + ULONG PhysicalAddress; + UCHAR i; + KIRQL OldIrql; + + KeAcquireSpinLock(&hcd->Lock, &OldIrql); + + Descriptor = (PQUEUE_TRANSFER_DESCRIPTOR)AllocateMemory(hcd, sizeof(QUEUE_TRANSFER_DESCRIPTOR), &PhysicalAddress); + RtlZeroMemory(Descriptor, sizeof(QUEUE_TRANSFER_DESCRIPTOR)); + Descriptor->NextPointer = TERMINATE_POINTER; + Descriptor->AlternateNextPointer = TERMINATE_POINTER; + Descriptor->Token.Bits.DataToggle = TRUE; + Descriptor->Token.Bits.InterruptOnComplete = TRUE; + Descriptor->Token.Bits.ErrorCounter = 0x03; + Descriptor->Token.Bits.Active = TRUE; + Descriptor->Token.Bits.PIDCode = PIDCode; + Descriptor->Token.Bits.TotalBytesToTransfer = TotalBytesToTransfer; + Descriptor->PhysicalAddr = PhysicalAddress; + for (i=0;i<5;i++) + Descriptor->BufferPointer[i] = 0; + + KeReleaseSpinLock(&hcd->Lock, OldIrql); + + return Descriptor; +} + +VOID +FreeDescriptor(PQUEUE_TRANSFER_DESCRIPTOR Descriptor) +{ + ReleaseMemory((ULONG)Descriptor); +} + +/* Queue Head */ + +VOID +DumpQueueHeadList(PEHCI_HOST_CONTROLLER hcd) +{ + KIRQL OldIrql; + + KeAcquireSpinLock(&hcd->Lock, &OldIrql); + + PQUEUE_HEAD QueueHead = (PQUEUE_HEAD)hcd->CommonBufferVA; + PQUEUE_HEAD FirstQueueHead = QueueHead; + DPRINT1("Dumping QueueHead List!!!!!!!!!!!!!\n"); + while (1) + { + DPRINT1("QueueHead Address %x\n", QueueHead); + DPRINT1("QueueHead->PreviousQueueHead = %x\n", QueueHead->PreviousQueueHead); + DPRINT1("QueueHead->NextQueueHead = %x\n", QueueHead->NextQueueHead); + DPRINT1(" ---> PhysicalAddress %x\n", (ULONG)MmGetPhysicalAddress(QueueHead).LowPart); + DPRINT1("QueueHead->HorizontalLinkPointer %x\n", QueueHead->HorizontalLinkPointer); + QueueHead = QueueHead->NextQueueHead; + DPRINT1("Next QueueHead %x\n", QueueHead); + if (QueueHead == FirstQueueHead) break; + } + DPRINT1("-----------------------------------\n"); + KeReleaseSpinLock(&hcd->Lock, OldIrql); +} + +PQUEUE_HEAD +CreateQueueHead(PEHCI_HOST_CONTROLLER hcd) +{ + PQUEUE_HEAD CurrentQH; + ULONG PhysicalAddress , i; + KIRQL OldIrql; + + KeAcquireSpinLock(&hcd->Lock, &OldIrql); + + CurrentQH = (PQUEUE_HEAD)AllocateMemory(hcd, sizeof(QUEUE_HEAD), &PhysicalAddress); + RtlZeroMemory(CurrentQH, sizeof(QUEUE_HEAD)); + + ASSERT(CurrentQH); + CurrentQH->PhysicalAddr = PhysicalAddress; + CurrentQH->HorizontalLinkPointer = TERMINATE_POINTER; + CurrentQH->CurrentLinkPointer = TERMINATE_POINTER; + CurrentQH->AlternateNextPointer = TERMINATE_POINTER; + CurrentQH->NextPointer = TERMINATE_POINTER; + + /* 1 for non high speed, 0 for high speed device */ + CurrentQH->EndPointCharacteristics.ControlEndPointFlag = 0; + CurrentQH->EndPointCharacteristics.HeadOfReclamation = FALSE; + CurrentQH->EndPointCharacteristics.MaximumPacketLength = 64; + + /* Set NakCountReload to max value possible */ + CurrentQH->EndPointCharacteristics.NakCountReload = 0xF; + + /* Get the Initial Data Toggle from the QEDT */ + CurrentQH->EndPointCharacteristics.QEDTDataToggleControl = TRUE; + + /* High Speed Device */ + CurrentQH->EndPointCharacteristics.EndPointSpeed = QH_ENDPOINT_HIGHSPEED; + + CurrentQH->EndPointCapabilities.NumberOfTransactionPerFrame = 0x03; + + CurrentQH->Token.DWord = 0; + CurrentQH->NextQueueHead = NULL; + CurrentQH->PreviousQueueHead = NULL; + for (i=0; i<5; i++) + CurrentQH->BufferPointer[i] = 0; + + CurrentQH->Token.Bits.InterruptOnComplete = TRUE; + + KeReleaseSpinLock(&hcd->Lock, OldIrql); + return CurrentQH; +} + +VOID +LinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead) +{ + KIRQL OldIrql; + PQUEUE_HEAD CurrentHead = (PQUEUE_HEAD)hcd->AsyncListQueue; + PQUEUE_HEAD PreviousHead = CurrentHead->PreviousQueueHead; + + KeAcquireSpinLock(&hcd->Lock, &OldIrql); + + QueueHead->HorizontalLinkPointer = (CurrentHead->HorizontalLinkPointer | QH_TYPE_QH) & ~TERMINATE_POINTER; + QueueHead->NextQueueHead = CurrentHead; + QueueHead->PreviousQueueHead = PreviousHead; + + CurrentHead->PreviousQueueHead = QueueHead; + if (PreviousHead) + PreviousHead->NextQueueHead = QueueHead; + + CurrentHead->HorizontalLinkPointer = QueueHead->PhysicalAddr | QH_TYPE_QH; + + KeReleaseSpinLock(&hcd->Lock, OldIrql); +} + +VOID +UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead) +{ + KIRQL OldIrql; + PQUEUE_HEAD PreviousHead = QueueHead->PreviousQueueHead; + PQUEUE_HEAD NextHead = QueueHead->NextQueueHead; + KeAcquireSpinLock(&hcd->Lock, &OldIrql); + + if (PreviousHead) + { + PreviousHead->NextQueueHead = NextHead; + PreviousHead->HorizontalLinkPointer = QueueHead->HorizontalLinkPointer; + } + if (NextHead) + NextHead->PreviousQueueHead = PreviousHead; + + KeReleaseSpinLock(&hcd->Lock, OldIrql); +} + +VOID +DeleteQueueHead(PQUEUE_HEAD QueueHead) +{ + ReleaseMemory((ULONG)QueueHead); +} +
Propchange: trunk/reactos/drivers/usb/usbehci/hwiface.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/drivers/usb/usbehci/hwiface.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbehci/hwiface... ============================================================================== --- trunk/reactos/drivers/usb/usbehci/hwiface.h (added) +++ trunk/reactos/drivers/usb/usbehci/hwiface.h [iso-8859-1] Fri Dec 31 12:01:21 2010 @@ -1,0 +1,24 @@ +#include "hardware.h" +#include <ntddk.h> + +PQUEUE_TRANSFER_DESCRIPTOR +CreateDescriptor(PEHCI_HOST_CONTROLLER hcd, UCHAR PIDCode, ULONG TotalBytesToTransfer); + +VOID +FreeDescriptor(PQUEUE_TRANSFER_DESCRIPTOR Descriptor); + +VOID +DumpQueueHeadList(PEHCI_HOST_CONTROLLER hcd); + +PQUEUE_HEAD +CreateQueueHead(PEHCI_HOST_CONTROLLER hcd); + +VOID +LinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead); + +VOID +UnlinkQueueHead(PEHCI_HOST_CONTROLLER hcd, PQUEUE_HEAD QueueHead); + +VOID +DeleteQueueHead(PQUEUE_HEAD QueueHead); +
Propchange: trunk/reactos/drivers/usb/usbehci/hwiface.h ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/drivers/usb/usbehci/transfer.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbehci/transfe... ============================================================================== --- trunk/reactos/drivers/usb/usbehci/transfer.c (added) +++ trunk/reactos/drivers/usb/usbehci/transfer.c [iso-8859-1] Fri Dec 31 12:01:21 2010 @@ -1,0 +1,217 @@ +/* + * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface + * LICENSE: GPL - See COPYING in the top level directory + * FILE: drivers/usb/usbehci/transfer.c + * PURPOSE: Transfers to EHCI. + * PROGRAMMERS: + * Michael Martin (michael.martin@reactos.org) + */ + +#include "transfer.h" +#include <debug.h> + +VOID +BuildSetupPacketFromURB(PEHCI_HOST_CONTROLLER hcd, PURB Urb, PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup) +{ + switch (Urb->UrbHeader.Function) + { + /* CLEAR FEATURE */ + case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: + DPRINT1("Not implemented!\n"); + break; + + /* GET CONFIG */ + case URB_FUNCTION_GET_CONFIGURATION: + CtrlSetup->bRequest = USB_REQUEST_GET_CONFIGURATION; + CtrlSetup->bmRequestType.B = 0x80; + CtrlSetup->wLength = 1; + break; + + /* GET DESCRIPTOR */ + case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: + CtrlSetup->bRequest = USB_REQUEST_GET_DESCRIPTOR; + CtrlSetup->wValue.LowByte = Urb->UrbControlDescriptorRequest.Index; + CtrlSetup->wValue.HiByte = Urb->UrbControlDescriptorRequest.DescriptorType; + CtrlSetup->wIndex.W = Urb->UrbControlDescriptorRequest.LanguageId; + CtrlSetup->wLength = Urb->UrbControlDescriptorRequest.TransferBufferLength; + CtrlSetup->bmRequestType.B = 0x80; + break; + + /* GET INTERFACE */ + case URB_FUNCTION_GET_INTERFACE: + CtrlSetup->bRequest = USB_REQUEST_GET_CONFIGURATION; + CtrlSetup->wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup->bmRequestType.B = 0x80; + CtrlSetup->wLength = 1; + break; + + /* GET STATUS */ + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: + CtrlSetup->bRequest = USB_REQUEST_GET_STATUS; + ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); + CtrlSetup->wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup->bmRequestType.B = 0x80; + CtrlSetup->wLength = 2; + break; + + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: + CtrlSetup->bRequest = USB_REQUEST_GET_STATUS; + ASSERT(Urb->UrbControlGetStatusRequest.Index != 0); + CtrlSetup->wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup->bmRequestType.B = 0x81; + CtrlSetup->wLength = 2; + break; + + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: + CtrlSetup->bRequest = USB_REQUEST_GET_STATUS; + ASSERT(Urb->UrbControlGetStatusRequest.Index != 0); + CtrlSetup->wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup->bmRequestType.B = 0x82; + CtrlSetup->wLength = 2; + break; + + /* SET ADDRESS */ + + /* SET CONFIG */ + case URB_FUNCTION_SELECT_CONFIGURATION: + CtrlSetup->bRequest = USB_REQUEST_SET_CONFIGURATION; + CtrlSetup->bmRequestType.B = 0x00; + break; + + /* SET DESCRIPTOR */ + case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: + case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: + case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: + DPRINT1("Not implemented\n"); + break; + + /* SET FEATURE */ + case URB_FUNCTION_SET_FEATURE_TO_DEVICE: + CtrlSetup->bRequest = USB_REQUEST_SET_FEATURE; + ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); + CtrlSetup->wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup->bmRequestType.B = 0x80; + break; + + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: + CtrlSetup->bRequest = USB_REQUEST_SET_FEATURE; + ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); + CtrlSetup->wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup->bmRequestType.B = 0x81; + break; + + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: + CtrlSetup->bRequest = USB_REQUEST_SET_FEATURE; + ASSERT(Urb->UrbControlGetStatusRequest.Index == 0); + CtrlSetup->wIndex.W = Urb->UrbControlGetStatusRequest.Index; + CtrlSetup->bmRequestType.B = 0x82; + break; + + /* SET INTERFACE*/ + case URB_FUNCTION_SELECT_INTERFACE: + DPRINT1("Not implemented\n"); + break; + + /* SYNC FRAME */ + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: + DPRINT1("Not implemented\n"); + break; + default: + DPRINT1("Unknown USB Request!\n"); + break; + } +} + +BOOLEAN +SubmitControlTransfer(PEHCI_HOST_CONTROLLER hcd, + PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup, + PVOID TransferBuffer, + ULONG TransferBufferLength, + PIRP IrpToComplete) +{ + PQUEUE_HEAD QueueHead; + PQUEUE_TRANSFER_DESCRIPTOR Descriptor[3]; + ULONG MdlPhysicalAddr; + PKEVENT Event = NULL; + PMDL pMdl = NULL; + PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetupVA, CtrlPhysicalPA; + + CtrlSetupVA = (PUSB_DEFAULT_PIPE_SETUP_PACKET)AllocateMemory(hcd, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), + (ULONG*)&CtrlPhysicalPA); + + RtlCopyMemory(CtrlSetupVA, CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + /* If no Irp then wait on completion */ + if (IrpToComplete == NULL) + { + Event = ExAllocatePool(NonPagedPool, sizeof(KEVENT)); + KeInitializeEvent(Event, NotificationEvent, FALSE); + } + + /* Allocate Mdl for Buffer */ + pMdl = IoAllocateMdl(TransferBuffer, + TransferBufferLength, + FALSE, + FALSE, + NULL); + + /* Lock Physical Pages */ + MmBuildMdlForNonPagedPool(pMdl); + //MmProbeAndLockPages(pMdl, KernelMode, IoReadAccess); + + MdlPhysicalAddr = MmGetPhysicalAddress((PVOID)TransferBuffer).LowPart; + + QueueHead = CreateQueueHead(hcd); + + Descriptor[0] = CreateDescriptor(hcd, + PID_CODE_SETUP_TOKEN, + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET)); + + Descriptor[0]->Token.Bits.InterruptOnComplete = FALSE; + Descriptor[0]->Token.Bits.DataToggle = FALSE; + + /* Save the first descriptor */ + QueueHead->TransferDescriptor = Descriptor[0]; + + Descriptor[1] = CreateDescriptor(hcd, + PID_CODE_IN_TOKEN, + TransferBufferLength); + + Descriptor[2] = CreateDescriptor(hcd, + PID_CODE_OUT_TOKEN, + 0); + + Descriptor[1]->Token.Bits.InterruptOnComplete = FALSE; + + /* Link the descriptors */ + Descriptor[0]->NextDescriptor = Descriptor[1]; + Descriptor[1]->NextDescriptor = Descriptor[2]; + Descriptor[1]->PreviousDescriptor = Descriptor[0]; + Descriptor[2]->PreviousDescriptor = Descriptor[1]; + + /* Assign the descritors buffers */ + Descriptor[0]->BufferPointer[0] = (ULONG)CtrlPhysicalPA; + Descriptor[1]->BufferPointer[0] = MdlPhysicalAddr; + + Descriptor[0]->NextPointer = Descriptor[1]->PhysicalAddr; + Descriptor[1]->NextPointer = Descriptor[2]->PhysicalAddr; + QueueHead->NextPointer = Descriptor[0]->PhysicalAddr; + + QueueHead->IrpToComplete = IrpToComplete; + QueueHead->MdlToFree = pMdl; + QueueHead->Event = Event; + + /* Link in the QueueHead */ + LinkQueueHead(hcd, QueueHead); + + if (IrpToComplete == NULL) + { + DPRINT1("Waiting For Completion %x!\n", Event); + KeWaitForSingleObject(Event, Suspended, KernelMode, FALSE, NULL); + ExFreePool(Event); + } + + return TRUE; +}
Propchange: trunk/reactos/drivers/usb/usbehci/transfer.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/drivers/usb/usbehci/transfer.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/usb/usbehci/transfe... ============================================================================== --- trunk/reactos/drivers/usb/usbehci/transfer.h (added) +++ trunk/reactos/drivers/usb/usbehci/transfer.h [iso-8859-1] Fri Dec 31 12:01:21 2010 @@ -1,0 +1,20 @@ +#pragma once + +#include "hardware.h" +#include "hwiface.h" +#include "physmem.h" +#include <usb.h> +#include <ntddk.h> + +BOOLEAN +SubmitControlTransfer(PEHCI_HOST_CONTROLLER hcd, + PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup, + PVOID TransferBuffer, + ULONG TransferBufferLength, + PIRP IrpToComplete); + +VOID +BuildSetupPacketFromURB(PEHCI_HOST_CONTROLLER hcd, + PURB Urb, + PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup); +
Propchange: trunk/reactos/drivers/usb/usbehci/transfer.h ------------------------------------------------------------------------------ svn:eol-style = native