964 lines
23 KiB
C
964 lines
23 KiB
C
/*++
|
|
|
|
Copyright (c) 1995,1996 Microsoft Corporation
|
|
:ts=4
|
|
|
|
Module Name:
|
|
|
|
hub.c
|
|
|
|
Abstract:
|
|
|
|
The UHC driver for USB, this module contains the root hub
|
|
interface code.
|
|
|
|
Environment:
|
|
|
|
kernel mode only
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
2-08-96 : created
|
|
|
|
--*/
|
|
|
|
#include "wdm.h"
|
|
#include "stdarg.h"
|
|
#include "stdio.h"
|
|
|
|
#include "usbdi.h"
|
|
#include "hcdi.h"
|
|
#include "uhcd.h"
|
|
|
|
typedef struct _ROOT_HUB_TIMER {
|
|
KTIMER Timer;
|
|
KDPC Dpc;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PROOTHUB_TIMER_ROUTINE TimerRoutine;
|
|
PVOID Context;
|
|
} ROOT_HUB_TIMER, *PROOT_HUB_TIMER;
|
|
|
|
|
|
NTSTATUS
|
|
UHCD_RootHub_OpenEndpoint(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PHCD_URB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called at Dispatch level
|
|
to process commands bound for the root hub.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object
|
|
|
|
Irp - pointer to an I/O Request Packet
|
|
|
|
Urb - urb for this request
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_ENDPOINT endpoint;
|
|
PUSB_ENDPOINT_DESCRIPTOR endpointDescriptor;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_RootHub_OpenEndpoint\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
LOGENTRY(LOG_MISC, 'rhOE', deviceExtension, 0, 0);
|
|
|
|
endpoint = (PUHCD_ENDPOINT) GETHEAP(NonPagedPool,
|
|
sizeof(UHCD_ENDPOINT));
|
|
if (endpoint) {
|
|
|
|
//
|
|
// initialize endpoint structures, state variables.
|
|
//
|
|
|
|
// start endpoint initialization
|
|
RtlZeroMemory(endpoint, sizeof(*endpoint));
|
|
endpoint->Sig = SIG_EP;
|
|
SET_EPFLAG(endpoint, EPFLAG_ROOT_HUB);
|
|
|
|
endpointDescriptor = Urb->HcdUrbOpenEndpoint.EndpointDescriptor;
|
|
endpoint->MaxRequests = MAX_REQUESTS(endpointDescriptor,
|
|
endpoint->EndpointFlags);
|
|
|
|
ntStatus = UHCD_FinishInitializeEndpoint(DeviceObject,
|
|
endpoint,
|
|
endpointDescriptor,
|
|
Urb);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
Urb->HcdUrbOpenEndpoint.HcdEndpoint = endpoint;
|
|
URB_HEADER(Urb).Status = USBD_STATUS_SUCCESS;
|
|
|
|
//
|
|
// if this is the interrupt endpoint start a timer Dpc to be called
|
|
// based on the endpoint polling interval.
|
|
//
|
|
|
|
if (endpoint->Type == USB_ENDPOINT_TYPE_INTERRUPT) {
|
|
LARGE_INTEGER dueTime;
|
|
LONG period;
|
|
|
|
endpoint->Interval = endpointDescriptor->bInterval;
|
|
UHCD_ASSERT(endpoint->Interval != 0);
|
|
|
|
deviceExtension->RootHubInterruptEndpoint = endpoint;
|
|
KeInitializeTimer(&deviceExtension->RootHubPollTimer);
|
|
KeInitializeDpc(&deviceExtension->RootHubPollDpc,
|
|
UHCD_RootHubPollDpc,
|
|
DeviceObject);
|
|
|
|
deviceExtension->RootHubPollTimerInitialized = TRUE;
|
|
|
|
dueTime.QuadPart = -10000 * endpoint->Interval;
|
|
period = 100; //every 100 ms
|
|
|
|
UHCD_KdPrint((2, "'UHCD Poll Interval = (0x%x) %x %x\n",
|
|
endpoint->Interval, dueTime.LowPart, dueTime.HighPart));
|
|
|
|
KeSetTimerEx(&deviceExtension->RootHubPollTimer,
|
|
dueTime,
|
|
period,
|
|
&deviceExtension->RootHubPollDpc);
|
|
|
|
}
|
|
} else {
|
|
RETHEAP(endpoint);
|
|
}
|
|
}
|
|
|
|
UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_RootHub_OpenEndpoint (%x)\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
UHCD_RootHub_CloseEndpoint(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PHCD_URB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called at Dispatch level
|
|
to process commands bound for the root hub.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object
|
|
|
|
Irp - pointer to an I/O Request Packet
|
|
|
|
Urb - urb for this request
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_ENDPOINT endpoint;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_RootHub_CloseEndpoint\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
endpoint = Urb->HcdUrbCloseEndpoint.HcdEndpoint;
|
|
ASSERT_ENDPOINT(endpoint);
|
|
|
|
if (endpoint->ActiveTransfers[0]) {
|
|
URB_HEADER(Urb).Status = USBD_STATUS_ERROR_BUSY;
|
|
} else {
|
|
|
|
if (endpoint == deviceExtension->RootHubInterruptEndpoint) {
|
|
// closing the interrupt endpoint,
|
|
// this means the root hub is stopped
|
|
deviceExtension->RootHubDeviceAddress = USB_DEFAULT_DEVICE_ADDRESS;
|
|
|
|
// if the timer fires before we cancel it then this
|
|
// will stop the polling process
|
|
deviceExtension->RootHubInterruptEndpoint = NULL;
|
|
// if this is the interrupt endpoint kill the timer here
|
|
KeCancelTimer(&deviceExtension->RootHubPollTimer);
|
|
}
|
|
|
|
RETHEAP(endpoint);
|
|
|
|
URB_HEADER(Urb).Status = USBD_STATUS_SUCCESS;
|
|
}
|
|
|
|
UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, NULL);
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_RootHub_CloseEndpoint (%x)\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
UHCD_RootHub_ControlTransfer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PHCD_URB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called at Dispatch level
|
|
to process commands bound for the root hub.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object
|
|
|
|
Irp - pointer to an I/O Request Packet
|
|
|
|
Urb - urb for this request
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_ENDPOINT endpoint;
|
|
RHSTATUS rootHubReturnCode;
|
|
KIRQL irql;
|
|
PVOID mappedSystemVa;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_RootHub_ControlTransfer\n"));
|
|
|
|
INCREMENT_PENDING_URB_COUNT(Irp);
|
|
|
|
IoAcquireCancelSpinLock(&irql);
|
|
if (Irp->Cancel) {
|
|
TEST_TRAP();
|
|
//BUGBUG Irp was canceled
|
|
IoReleaseCancelSpinLock(irql);
|
|
UHCD_CompleteIrp(DeviceObject, Irp, STATUS_CANCELLED, 0, Urb);
|
|
goto UHCD_RootHub_ControlTransfer_Done;
|
|
|
|
} else {
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
IoReleaseCancelSpinLock(irql);
|
|
}
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
endpoint = HCD_AREA(Urb).HcdEndpoint;
|
|
ASSERT_ENDPOINT(endpoint);
|
|
|
|
// NOTE:
|
|
// should not get control transfers for anything but
|
|
// the default pipe
|
|
//
|
|
|
|
UHCD_ASSERT(endpoint->EndpointAddress == 0);
|
|
|
|
//BUGBUG no support for linked URBs yet
|
|
UHCD_ASSERT(Urb->HcdUrbCommonTransfer.UrbLink == NULL);
|
|
|
|
if (endpoint->EndpointAddress != 0) {
|
|
URB_HEADER(Urb).Status = USBD_STATUS_INVALID_PARAMETER;
|
|
} else {
|
|
|
|
//
|
|
// convert transfer buffer from MDL
|
|
//
|
|
mappedSystemVa =
|
|
Urb->HcdUrbCommonTransfer.TransferBufferLength ?
|
|
Urb->HcdUrbCommonTransfer.TransferBufferMDL->MappedSystemVa :
|
|
NULL;
|
|
|
|
//UHCD_KdPrint((2, "' Mapped systemVa = 0x%x \n", mappedSystemVa));
|
|
rootHubReturnCode =
|
|
RootHub_Endpoint0(deviceExtension->RootHub,
|
|
(PRH_SETUP)Urb->HcdUrbCommonTransfer.Extension.u.SetupPacket,
|
|
(PUCHAR) &deviceExtension->RootHubDeviceAddress,
|
|
mappedSystemVa,
|
|
&Urb->HcdUrbCommonTransfer.TransferBufferLength);
|
|
|
|
switch (rootHubReturnCode) {
|
|
case RH_SUCCESS:
|
|
URB_HEADER(Urb).Status = USBD_STATUS_SUCCESS;
|
|
#if DBG
|
|
// restore the original transfer buffer address
|
|
Urb->HcdUrbCommonTransfer.TransferBuffer =
|
|
mappedSystemVa;
|
|
#endif
|
|
break;
|
|
case RH_NAK:
|
|
case RH_STALL:
|
|
// return stall error and set the endpoint state to
|
|
// stalled on the host side
|
|
if (endpoint->EndpointFlags & EPFLAG_NO_HALT) {
|
|
URB_HEADER(Urb).Status =
|
|
USBD_STATUS(USBD_STATUS_STALL_PID)
|
|
| USBD_STATUS_ERROR;
|
|
} else {
|
|
SET_EPFLAG(endpoint, EPFLAG_HOST_HALTED);
|
|
URB_HEADER(Urb).Status = USBD_STATUS_STALL_PID;
|
|
}
|
|
//
|
|
// if we get here it is probably a bug in the root hub
|
|
// code or the hub driver.
|
|
//
|
|
UHCD_KdTrap(("Root hub stalled request\n"));
|
|
}
|
|
}
|
|
|
|
UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, Urb);
|
|
|
|
UHCD_RootHub_ControlTransfer_Done:
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_RootHub_ControlTransfer (%x)\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
UHCD_RootHub_InterruptTransfer(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PHCD_URB Urb
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called at Dispatch level
|
|
to process commands bound for the root hub.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object
|
|
|
|
Irp - pointer to an I/O Request Packet
|
|
|
|
Urb - urb for this request
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PUHCD_ENDPOINT endpoint;
|
|
KIRQL irql;
|
|
PHCD_EXTENSION urbWork;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_RootHub_InterruptTransfer\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
INCREMENT_PENDING_URB_COUNT(Irp);
|
|
endpoint = HCD_AREA(Urb).HcdEndpoint;
|
|
ASSERT_ENDPOINT(endpoint);
|
|
ASSERT(HCD_AREA(Urb).HcdExtension != NULL);
|
|
|
|
urbWork = HCD_AREA(Urb).HcdExtension;
|
|
// set interrupt transfer to active.
|
|
urbWork->Flags |= UHCD_TRANSFER_ACTIVE;
|
|
|
|
//
|
|
// BUGBUG
|
|
// we only allow one transfer outstanding
|
|
// at a time here.
|
|
//
|
|
|
|
if (endpoint->ActiveTransfers[0] != NULL) {
|
|
TEST_TRAP();
|
|
|
|
URB_HEADER(Urb).Status = USBD_STATUS_REQUEST_FAILED;
|
|
UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, Urb);
|
|
|
|
} else if (Urb->HcdUrbCommonTransfer.UrbLink != NULL) {
|
|
TEST_TRAP();
|
|
|
|
URB_HEADER(Urb).Status = USBD_STATUS_INVALID_PARAMETER;
|
|
UHCD_CompleteIrp(DeviceObject, Irp, ntStatus, 0, Urb);
|
|
} else {
|
|
endpoint->ActiveTransfers[0] = Urb;
|
|
URB_HEADER(Urb).Status = UHCD_STATUS_PENDING_CURRENT;
|
|
|
|
//
|
|
// set up a cancel routine
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&irql);
|
|
if (Irp->Cancel) {
|
|
TEST_TRAP();
|
|
//BUGBUG Irp was canceled
|
|
IoReleaseCancelSpinLock(irql);
|
|
|
|
// call cancel routine
|
|
UHCD_RootHub_InterruptTransferCancel(DeviceObject, Irp);
|
|
|
|
goto UHCD_RootHub_InterruptTransfer_Done;
|
|
|
|
} else {
|
|
IoSetCancelRoutine(Irp, UHCD_RootHub_InterruptTransferCancel);
|
|
IoReleaseCancelSpinLock(irql);
|
|
}
|
|
|
|
ntStatus = STATUS_PENDING;
|
|
|
|
UHCD_KdPrint((2, "'Pending transfer for root hub\n"));
|
|
|
|
Irp->IoStatus.Status = ntStatus;
|
|
Irp->IoStatus.Information = 0;
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
|
|
UHCD_RootHub_InterruptTransfer_Done:
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_RootHub_InterruptTransfer (%x)\n", ntStatus));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_RootHubPoll(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUHCD_ENDPOINT Endpoint
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called at DPC level from the ISR DPC routine
|
|
to process transfers queued to for the root hub.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
PHCD_URB urb;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIRP irp;
|
|
RHSTATUS rootHubReturnCode;
|
|
BOOLEAN completeIt = TRUE;
|
|
KIRQL irql;
|
|
PVOID mappedSystemVa;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
//UHCD_KdPrint((2, "'enter UHCD_RootHub_Poll\n"));
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// See if we need to poll an endpoint for the
|
|
// root hub.
|
|
//
|
|
// if the current PM state is not 'ON' we will not poll the endpoint
|
|
// it means the HC has not fully resumed yet.
|
|
//
|
|
|
|
if (Endpoint &&
|
|
deviceExtension->CurrentDevicePowerState == PowerDeviceD0) {
|
|
|
|
// Yes, poll
|
|
ASSERT_ENDPOINT(Endpoint);
|
|
|
|
urb = Endpoint->ActiveTransfers[0];
|
|
|
|
// see if we have an abort request
|
|
if ((Endpoint->EndpointFlags & EPFLAG_ABORT_PENDING_TRANSFERS) && urb) {
|
|
CLR_EPFLAG(Endpoint, EPFLAG_ABORT_PENDING_TRANSFERS);
|
|
urb->HcdUrbCommonTransfer.Status =
|
|
USBD_STATUS_CANCELED;
|
|
completeIt = TRUE;
|
|
// BUGBUG do we need the error bit set here?
|
|
} else if (urb) {
|
|
//
|
|
// convert transfer buffer from MDL
|
|
//
|
|
|
|
|
|
if (urb->HcdUrbCommonTransfer.TransferBufferLength != 0) {
|
|
urb->HcdUrbCommonTransfer.TransferBufferMDL->MdlFlags
|
|
|= MDL_MAPPING_CAN_FAIL;
|
|
|
|
mappedSystemVa =
|
|
MmGetSystemAddressForMdl(urb->HcdUrbCommonTransfer
|
|
.TransferBufferMDL);
|
|
|
|
urb->HcdUrbCommonTransfer.TransferBufferMDL->MdlFlags
|
|
&= ~MDL_MAPPING_CAN_FAIL;
|
|
|
|
if (mappedSystemVa == NULL) {
|
|
rootHubReturnCode = RH_STALL;
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto UHCD_RootHubPollError;
|
|
}
|
|
} else{
|
|
mappedSystemVa = NULL;
|
|
}
|
|
|
|
|
|
//UHCD_KdPrint((2, "' Mapped systemVa = 0x%x \n", mappedSystemVa));
|
|
rootHubReturnCode =
|
|
RootHub_Endpoint1(deviceExtension->RootHub, mappedSystemVa,
|
|
&urb->HcdUrbCommonTransfer
|
|
.TransferBufferLength);
|
|
//
|
|
// set urb error code if necessary
|
|
//
|
|
|
|
switch (rootHubReturnCode) {
|
|
case RH_SUCCESS:
|
|
urb->HcdUrbCommonTransfer.Status = USBD_STATUS_SUCCESS;
|
|
#if DBG
|
|
// restore the original transfer buffer address
|
|
urb->HcdUrbCommonTransfer.TransferBuffer =
|
|
mappedSystemVa;
|
|
#endif
|
|
break;
|
|
|
|
case RH_STALL:
|
|
if (Endpoint->EndpointFlags & EPFLAG_NO_HALT) {
|
|
// if we dont halt clear th ehalt bit on
|
|
// the error code
|
|
URB_HEADER(urb).Status =
|
|
USBD_STATUS(USBD_STATUS_STALL_PID) | USBD_STATUS_ERROR;
|
|
} else {
|
|
SET_EPFLAG(Endpoint, EPFLAG_HOST_HALTED);
|
|
URB_HEADER(urb).Status = USBD_STATUS_STALL_PID;
|
|
}
|
|
//
|
|
// if we get here it is probably a bug in the root hub code
|
|
//
|
|
UHCD_KdTrap(("root hub stalled request\n"));
|
|
break;
|
|
case RH_NAK:
|
|
// NAK, don't complete request
|
|
completeIt = FALSE;
|
|
break;
|
|
default:
|
|
UHCD_KdTrap(("bogus return code from RootHub_Endpoint1\n"));
|
|
}
|
|
|
|
} else {
|
|
// no transfer, same as NAK
|
|
completeIt = FALSE;
|
|
}
|
|
|
|
UHCD_RootHubPollError:;
|
|
if (completeIt) {
|
|
UHCD_ASSERT(urb != NULL);
|
|
|
|
//
|
|
// Remove the Irp from the cancelable state
|
|
// before passing it to the Root Hub Code.
|
|
//
|
|
irp = HCD_AREA(urb).HcdIrp;
|
|
|
|
IoAcquireCancelSpinLock(&irql);
|
|
if (irp->Cancel) {
|
|
TEST_TRAP();
|
|
//BUGBUG Irp was canceled
|
|
IoReleaseCancelSpinLock(irql);
|
|
|
|
UHCD_RootHub_InterruptTransferCancel(DeviceObject, irp);
|
|
|
|
} else {
|
|
IoSetCancelRoutine(irp, NULL);
|
|
IoReleaseCancelSpinLock(irql);
|
|
//
|
|
// have data or error, complete the irp
|
|
//
|
|
|
|
// BUGBUG we are not supporting queued
|
|
// transfers for the hub driver.
|
|
Endpoint->ActiveTransfers[0] = NULL;
|
|
|
|
UHCD_ASSERT(irp != NULL);
|
|
UHCD_CompleteIrp(DeviceObject,
|
|
irp,
|
|
status,
|
|
0,
|
|
urb);
|
|
}
|
|
}
|
|
}
|
|
|
|
//UHCD_KdPrint((2, "'exit UHCD_RootHub_Poll\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Root Hub Services
|
|
//
|
|
// These services are provided to the root
|
|
// hub code by UHCD.
|
|
//
|
|
|
|
USHORT
|
|
UHCD_RootHub_ReadPort(
|
|
IN PROOTHUB_PORT HubPort
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
returns the value of the requested hub
|
|
register for a given controller identified
|
|
by HcdPtr.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
USHORT dataVal;
|
|
|
|
deviceExtension = HubPort->DeviceObject->DeviceExtension;
|
|
|
|
dataVal = READ_PORT_USHORT(
|
|
(PUSHORT) (deviceExtension->DeviceRegisters[0] +
|
|
HubPort->Address));
|
|
|
|
// UHCD_KdPrint((2, "'RooHub -- read port %x\n", dataVal));
|
|
|
|
return dataVal;
|
|
}
|
|
|
|
|
|
//BUGBUG need a return code here
|
|
VOID
|
|
UHCD_RootHub_Timer(
|
|
IN PVOID HcdPtr,
|
|
IN LONG WaitTime,
|
|
IN PROOTHUB_TIMER_ROUTINE RootHubTimerRoutine,
|
|
IN PVOID TimerContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This Routine can only be called at passive level,
|
|
it iniializes a timer object and starts the timer
|
|
for the root hub code.
|
|
|
|
Arguments:
|
|
|
|
HcdPtr - pointer passed to the root hub code during
|
|
initialization.
|
|
|
|
WaitTime - time to wait before signaling (in ms)
|
|
|
|
RootHubTimerRoutine - root hub function to call
|
|
when timer expires.
|
|
|
|
TimerContext - context pointer passed to RootHubTimerRoutine
|
|
when timer expires.
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT deviceObject = HcdPtr;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
LARGE_INTEGER dueTime;
|
|
PROOT_HUB_TIMER rootHubTimer;
|
|
ULONG timerIncerent;
|
|
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
|
|
rootHubTimer = GETHEAP(NonPagedPool, sizeof(ROOT_HUB_TIMER));
|
|
|
|
// compute timeout value (convert millisec to nanosec)
|
|
|
|
UHCD_ASSERT(WaitTime == 10); // BUGBUG root hub should always use 10ms
|
|
|
|
timerIncerent = KeQueryTimeIncrement() - 1;
|
|
|
|
dueTime.HighPart = -1;
|
|
// round up to the next highest timer increment
|
|
dueTime.LowPart = -1 * (10000 * WaitTime + timerIncerent);
|
|
|
|
if (rootHubTimer) {
|
|
|
|
UHCD_KdPrint((2, "'roothub timer set %d (%x %x)\n", WaitTime,
|
|
dueTime.LowPart, dueTime.HighPart));
|
|
rootHubTimer->DeviceObject = deviceObject;
|
|
rootHubTimer->TimerRoutine = RootHubTimerRoutine;
|
|
rootHubTimer->Context = TimerContext;
|
|
deviceExtension->RootHubTimersActive++;
|
|
|
|
//BUGBUG Timer DPCs not working with NTKERN
|
|
//#ifdef NTKERN
|
|
//#pragma message ("warning: using workaround for bugs in ntkern")
|
|
// (VOID) KeDelayExecutionThread(KernelMode,
|
|
// FALSE,
|
|
// &dueTime);
|
|
|
|
// UHCD_RootHubTimerDpc(&rootHubTimer->Dpc,
|
|
// rootHubTimer,
|
|
// NULL,
|
|
// NULL);
|
|
|
|
//#else
|
|
KeInitializeTimer(&rootHubTimer->Timer);
|
|
KeInitializeDpc(&rootHubTimer->Dpc,
|
|
UHCD_RootHubTimerDpc,
|
|
rootHubTimer);
|
|
|
|
KeSetTimer(&rootHubTimer->Timer,
|
|
dueTime,
|
|
&rootHubTimer->Dpc);
|
|
|
|
//#endif
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_RootHubTimerDpc(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs at DISPATCH_LEVEL IRQL.
|
|
|
|
Arguments:
|
|
|
|
Dpc - Pointer to the DPC object.
|
|
|
|
DeferredContext - supplies the RootHubTimer.
|
|
|
|
SystemArgument1 - not used.
|
|
|
|
SystemArgument2 - not used.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PROOT_HUB_TIMER rootHubTimer = DeferredContext;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
UHCD_KdPrint((2, "'enter roothub timer Dpc\n"));
|
|
|
|
deviceExtension = rootHubTimer->DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// call the root hub code callback
|
|
//
|
|
|
|
rootHubTimer->TimerRoutine(rootHubTimer->Context);
|
|
|
|
UHCD_ASSERT(deviceExtension->RootHubTimersActive != 0);
|
|
|
|
deviceExtension->RootHubTimersActive--;
|
|
|
|
RETHEAP(rootHubTimer);
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_RootHub_WritePort(
|
|
IN PROOTHUB_PORT HubPort,
|
|
IN USHORT DataVal
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the root hub code to perform
|
|
writes to a specific HC register.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = HubPort->DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// mask off bits 13:15 (see UHCI design guide)
|
|
//
|
|
|
|
DataVal &= 0x1fff;
|
|
|
|
// UHCD_KdPrint((2, "'RooHub -- write port %x\n", DataVal));
|
|
|
|
WRITE_PORT_USHORT(
|
|
(PUSHORT) (deviceExtension->DeviceRegisters[0] +
|
|
HubPort->Address), DataVal);
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_RootHub_InterruptTransferCancel(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called to cancel at interrupt
|
|
transfer request pending in the root hub code .
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to a device object
|
|
|
|
Irp - pointer to an I/O Request Packet
|
|
|
|
Return Value:
|
|
|
|
NT status code.
|
|
|
|
--*/
|
|
{
|
|
|
|
PHCD_URB urb;
|
|
PUHCD_ENDPOINT endpoint;
|
|
|
|
UHCD_KdPrint((2, "'enter UHCD_RootHub_InterruptTransferCancel\n"));
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
urb = (PHCD_URB) URB_FROM_IRP(Irp);
|
|
|
|
// BUGBUG we are not supporting queued
|
|
// transfers for the hub driver.
|
|
endpoint = HCD_AREA(urb).HcdEndpoint;
|
|
ASSERT_ENDPOINT(endpoint);
|
|
endpoint->ActiveTransfers[0] = NULL;
|
|
|
|
UHCD_CompleteIrp(DeviceObject,
|
|
Irp,
|
|
STATUS_CANCELLED,
|
|
0,
|
|
urb);
|
|
|
|
UHCD_KdPrint((2, "'exit UHCD_RootHub_InterruptTransferCancel\n"));
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
UHCD_RootHubPollDpc(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine runs at DISPATCH_LEVEL IRQL.
|
|
|
|
Arguments:
|
|
|
|
Dpc - Pointer to the DPC object.
|
|
|
|
DeferredContext - supplies the device object.
|
|
|
|
SystemArgument1 - not used.
|
|
|
|
SystemArgument2 - not used.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_OBJECT deviceObject = DeferredContext;
|
|
PUHCD_ENDPOINT endpoint;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
|
|
deviceExtension = deviceObject->DeviceExtension;
|
|
endpoint = deviceExtension->RootHubInterruptEndpoint;
|
|
|
|
// LOGENTRY(LOG_MISC, 'rhpX', deviceExtension, 0, 0);
|
|
|
|
if (deviceExtension->InterruptObject) {
|
|
UHCD_IsrDpc(
|
|
NULL,
|
|
DeferredContext,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
UHCD_CheckIdle(deviceObject);
|
|
|
|
if (endpoint == NULL ||
|
|
(deviceExtension->HcFlags & HCFLAG_HCD_STOPPED)) {
|
|
// root hub has been closed, no more polling
|
|
// please.
|
|
LOGENTRY(LOG_MISC, 'rhpS', deviceExtension, 0,
|
|
deviceExtension->HcFlags);
|
|
|
|
return;
|
|
}
|
|
|
|
ASSERT_ENDPOINT(endpoint);
|
|
|
|
UHCD_RootHubPoll(deviceObject, endpoint);
|
|
|
|
}
|