mirror of
https://github.com/reactos/reactos.git
synced 2025-05-18 16:51:18 +00:00
[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. svn path=/trunk/; revision=50230
This commit is contained in:
parent
cb0b5d3b3a
commit
61f99c89a6
4 changed files with 436 additions and 0 deletions
175
reactos/drivers/usb/usbehci/hwiface.c
Normal file
175
reactos/drivers/usb/usbehci/hwiface.c
Normal file
|
@ -0,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);
|
||||
}
|
||||
|
24
reactos/drivers/usb/usbehci/hwiface.h
Normal file
24
reactos/drivers/usb/usbehci/hwiface.h
Normal file
|
@ -0,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);
|
||||
|
217
reactos/drivers/usb/usbehci/transfer.c
Normal file
217
reactos/drivers/usb/usbehci/transfer.c
Normal file
|
@ -0,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;
|
||||
}
|
20
reactos/drivers/usb/usbehci/transfer.h
Normal file
20
reactos/drivers/usb/usbehci/transfer.h
Normal file
|
@ -0,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);
|
||||
|
Loading…
Reference in a new issue