reactos/drivers/usb/usbehci/urbreq.c

217 lines
8.6 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbehci/urbreq.c
* PURPOSE: URB Related Functions.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
*/
#include "usbehci.h"
/* QueueHead must point to the base address in common buffer */
PVOID
IntializeHeadQueueForStandardRequest(PQUEUE_HEAD QueueHead,
PQUEUE_TRANSFER_DESCRIPTOR *CtrlTD1,
PQUEUE_TRANSFER_DESCRIPTOR *CtrlTD2,
PQUEUE_TRANSFER_DESCRIPTOR *CtrlTD3,
PUSB_DEFAULT_PIPE_SETUP_PACKET *CtrlSetup,
PVOID *CtrlData,
ULONG Size)
{
QueueHead->HorizontalLinkPointer = (ULONG)QueueHead | QH_TYPE_QH;
/* Set NakCountReload to max value possible */
QueueHead->EndPointCapabilities1.NakCountReload = 0xF;
/* 1 for non high speed, 0 for high speed device */
QueueHead->EndPointCapabilities1.ControlEndPointFlag = 0;
QueueHead->EndPointCapabilities1.HeadOfReclamation = TRUE;
QueueHead->EndPointCapabilities1.MaximumPacketLength = 64;
/* Get the Initial Data Toggle from the QEDT */
QueueHead->EndPointCapabilities1.QEDTDataToggleControl = TRUE;
/* HIGH SPEED DEVICE */
QueueHead->EndPointCapabilities1.EndPointSpeed = QH_ENDPOINT_HIGHSPEED;
QueueHead->EndPointCapabilities1.EndPointNumber = 0;
/* Only used for Periodic Schedule and Not High Speed devices.
Setting it to one result in undefined behavior for Async */
QueueHead->EndPointCapabilities1.InactiveOnNextTransaction = 0;
QueueHead->EndPointCapabilities1.DeviceAddress = 0;
QueueHead->EndPointCapabilities2.HubAddr = 0;
QueueHead->EndPointCapabilities2.NumberOfTransactionPerFrame = 0x01;
/* 0 For Async, 1 for periodoc schedule */
QueueHead->EndPointCapabilities2.InterruptScheduleMask = 0;
QueueHead->EndPointCapabilities2.PortNumber = 0;
QueueHead->EndPointCapabilities2.SplitCompletionMask = 0;
QueueHead->CurrentLinkPointer = 0;
QueueHead->QETDPointer = TERMINATE_POINTER;
QueueHead->AlternateNextPointer = TERMINATE_POINTER;
QueueHead->Token.Bits.InterruptOnComplete = TRUE;
QueueHead->BufferPointer[0] = 0;
QueueHead->BufferPointer[1] = 0;
QueueHead->BufferPointer[2] = 0;
QueueHead->BufferPointer[3] = 0;
QueueHead->BufferPointer[4] = 0;
/* Queue Head Initialized */
/* Queue Transfer Descriptors must be 32 byte aligned and reside in continous physical memory */
*CtrlTD1 = (PQUEUE_TRANSFER_DESCRIPTOR) (((ULONG)(QueueHead) + sizeof(QUEUE_HEAD) + 0x1F) & ~0x1F);
*CtrlTD2 = (PQUEUE_TRANSFER_DESCRIPTOR) (((ULONG)(*CtrlTD1) + sizeof(QUEUE_TRANSFER_DESCRIPTOR) + 0x1F) & ~0x1F);
*CtrlTD3 = (PQUEUE_TRANSFER_DESCRIPTOR) (((ULONG)(*CtrlTD2) + sizeof(QUEUE_TRANSFER_DESCRIPTOR) + 0x1F) & ~0x1F);
/* Must be Page aligned */
*CtrlSetup = (PUSB_DEFAULT_PIPE_SETUP_PACKET) (( (ULONG)(*CtrlTD3) + sizeof(QUEUE_TRANSFER_DESCRIPTOR) + 0xFFF) & ~0xFFF);
*CtrlData = (PVOID) (( (ULONG)(*CtrlSetup) + sizeof(USB_DEFAULT_PIPE_SETUP_PACKET) + 0xFFF) & ~0xFFF);
(*CtrlTD1)->NextPointer = TERMINATE_POINTER;
(*CtrlTD1)->AlternateNextPointer = TERMINATE_POINTER;
(*CtrlTD1)->BufferPointer[0] = (ULONG)MmGetPhysicalAddress((PVOID) (*CtrlSetup)).LowPart;
(*CtrlTD1)->Token.Bits.DataToggle = FALSE;
(*CtrlTD1)->Token.Bits.InterruptOnComplete = FALSE;
(*CtrlTD1)->Token.Bits.TotalBytesToTransfer = sizeof(USB_DEFAULT_PIPE_SETUP_PACKET);
(*CtrlTD1)->Token.Bits.ErrorCounter = 0x03;
(*CtrlTD1)->Token.Bits.PIDCode = PID_CODE_SETUP_TOKEN;
(*CtrlTD1)->Token.Bits.Active = TRUE;
(*CtrlTD2)->NextPointer = TERMINATE_POINTER;
(*CtrlTD2)->AlternateNextPointer = TERMINATE_POINTER;
if (Size == 0)
(*CtrlTD2)->BufferPointer[0] = 0;
else
(*CtrlTD2)->BufferPointer[0] = (ULONG)MmGetPhysicalAddress((PVOID) (*CtrlData)).LowPart;
(*CtrlTD2)->Token.Bits.DataToggle = TRUE;
(*CtrlTD2)->Token.Bits.InterruptOnComplete = TRUE;
(*CtrlTD2)->Token.Bits.TotalBytesToTransfer = Size;
(*CtrlTD2)->Token.Bits.ErrorCounter = 0x03;
(*CtrlTD2)->Token.Bits.PIDCode = PID_CODE_IN_TOKEN;
(*CtrlTD2)->Token.Bits.Active = TRUE;
(*CtrlTD1)->NextPointer = (ULONG)MmGetPhysicalAddress((PVOID)(*CtrlTD2)).LowPart;
(*CtrlTD3)->NextPointer = TERMINATE_POINTER;
(*CtrlTD3)->AlternateNextPointer = TERMINATE_POINTER;
(*CtrlTD3)->BufferPointer[0] = 0;
(*CtrlTD3)->Token.Bits.Active = TRUE;
(*CtrlTD3)->Token.Bits.PIDCode = PID_CODE_OUT_TOKEN;
(*CtrlTD3)->Token.Bits.InterruptOnComplete = TRUE;
(*CtrlTD3)->Token.Bits.TotalBytesToTransfer = 0;
(*CtrlTD3)->Token.Bits.DataToggle = TRUE;
(*CtrlTD3)->Token.Bits.ErrorCounter = 0x03;
(*CtrlTD2)->NextPointer = (ULONG) MmGetPhysicalAddress((PVOID)(*CtrlTD3)).LowPart;
return NULL;
}
BOOLEAN
ExecuteControlRequest(PFDO_DEVICE_EXTENSION DeviceExtension, PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, UCHAR Address, ULONG Port, PVOID Buffer, ULONG BufferLength)
{
PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup = NULL;
PVOID CtrlData = NULL;
PQUEUE_TRANSFER_DESCRIPTOR CtrlTD1 = NULL;
PQUEUE_TRANSFER_DESCRIPTOR CtrlTD2 = NULL;
PQUEUE_TRANSFER_DESCRIPTOR CtrlTD3 = NULL;
PQUEUE_HEAD QueueHead;
PEHCI_USBCMD_CONTENT UsbCmd;
PEHCI_USBSTS_CONTEXT UsbSts;
LONG Base;
LONG tmp;
DPRINT1("ExecuteControlRequest: Buffer %x, Length %x\n", Buffer, BufferLength);
ExAcquireFastMutex(&DeviceExtension->AsyncListMutex);
Base = (ULONG) DeviceExtension->ResourceMemory;
/* Set up the QUEUE HEAD in memory */
QueueHead = (PQUEUE_HEAD) ((ULONG)DeviceExtension->AsyncListQueueHeadPtr);
/* Initialize the memory pointers */
IntializeHeadQueueForStandardRequest(QueueHead,
&CtrlTD1,
&CtrlTD2,
&CtrlTD3,
&CtrlSetup,
(PVOID)&CtrlData,
BufferLength);
QueueHead->EndPointCapabilities2.PortNumber = Port;
QueueHead->EndPointCapabilities1.DeviceAddress = Address;
CtrlSetup->bmRequestType._BM.Recipient = SetupPacket->bmRequestType._BM.Recipient;
CtrlSetup->bmRequestType._BM.Type = SetupPacket->bmRequestType._BM.Type;
CtrlSetup->bmRequestType._BM.Dir = SetupPacket->bmRequestType._BM.Dir;
CtrlSetup->bRequest = SetupPacket->bRequest;
CtrlSetup->wValue.LowByte = SetupPacket->wValue.LowByte;
CtrlSetup->wValue.HiByte = SetupPacket->wValue.HiByte;
CtrlSetup->wIndex.W = SetupPacket->wIndex.W;
CtrlSetup->wLength = SetupPacket->wLength;
tmp = READ_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD));
UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
UsbCmd->Run = FALSE;
WRITE_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD), tmp);
/* Wait for the controller to halt */
for (;;)
{
KeStallExecutionProcessor(10);
tmp = READ_REGISTER_ULONG((PULONG)(Base + EHCI_USBSTS));
UsbSts = (PEHCI_USBSTS_CONTEXT)&tmp;
DPRINT("Waiting for Halt, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG)(Base + EHCI_USBSTS)));
if (UsbSts->HCHalted)
{
break;
}
}
/* Set to TRUE on interrupt for async completion */
DeviceExtension->AsyncComplete = FALSE;
QueueHead->QETDPointer = (ULONG) MmGetPhysicalAddress((PVOID)(CtrlTD1)).LowPart;
tmp = READ_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD));
UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
UsbCmd->AsyncEnable = TRUE;
WRITE_REGISTER_ULONG((PULONG)(Base + EHCI_USBCMD), tmp);
tmp = READ_REGISTER_ULONG((PULONG) (Base + EHCI_USBCMD));
UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
/* Interrupt on Async completion */
UsbCmd->DoorBell = TRUE;
UsbCmd->Run = TRUE;
WRITE_REGISTER_ULONG((PULONG)(Base + EHCI_USBCMD), tmp);
for (;;)
{
KeStallExecutionProcessor(100);
DPRINT("Waiting for completion!\n");
if (DeviceExtension->AsyncComplete == TRUE)
break;
}
UsbCmd->Run = FALSE;
WRITE_REGISTER_ULONG((PULONG)(Base + EHCI_USBCMD), tmp);
if (SetupPacket->bmRequestType._BM.Dir == BMREQUEST_DEVICE_TO_HOST)
{
if ((Buffer) && (BufferLength))
{
RtlCopyMemory(Buffer, CtrlData, BufferLength);
}
else
DPRINT1("Unable to copy data to buffer\n");
}
ExReleaseFastMutex(&DeviceExtension->AsyncListMutex);
return TRUE;
}