2020-09-30 17:17:25 +02:00

615 lines
19 KiB
C

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
ohcd.h
Abstract:
Structures used by the OpenHCI hardware dependent driver.
These are constructs specific to this driver implementation.
Standard Structures defined by Specification are in ohci.h
Environment:
Designed for XBOX.
Notes:
Revision History:
01-14-00 created by Mitchell Dernis (mitchd)
--*/
#ifndef __OCHD_H__
#define __OCHD_H__
//
// Pull in the hardware spec stuff
//
#include "ohci.h"
//
// forward declaration of pointer types, easy access later.
//
typedef struct _OHCD_TRANSFER_DESCRIPTOR *POHCD_TRANSFER_DESCRIPTOR;
typedef struct _OHCD_SETUP_BUFFER *POHCD_SETUP_BUFFER;
typedef struct _OHCD_ENDPOINT *POHCD_ENDPOINT;
typedef struct _OHCD_POOL *POHCD_POOL;
typedef struct _OHCD_INTERRUPT_SCHEDULE_NODE *POHCD_INTERRUPT_SCHEDULE_NODE;
typedef struct _OHCD_ENDPOINT_SCHEDULE *POHCD_ENDPOINT_SCHEDULE;
typedef struct _OHCD_DEVICE_EXTENSION *POHCD_DEVICE_EXTENSION;
//
// READ_REGISTER_ULONG and WRITE_REGISTER_ULONG are no longer
// support in the Xbox Kernel. Registers must be mapped to
// noncached memory. Define macros here that simply do
// a C assignement.
//
#define WRITE_REGISTER_ULONG(preg,value) (*((volatile ULONG *)(preg))=value)
#define READ_REGISTER_ULONG(preg) (*((volatile ULONG *)(preg)))
//
// struct OHCD_TRANSFER_DESCRIPTOR
//
// This is the transfer descriptor as seen by the OHCD driver.
// It is padded with 16 bytes of driver related fields.
// Followed by the OHCI defined structure.
//
typedef struct _OHCD_TRANSFER_DESCRIPTOR
{
//
// OHCI defined structure
//
OHCI_TRANSFER_DESCRIPTOR HcTransferDescriptor;
//
// 16 bytes of Extra driver related fields
//
ULONG PhysicalAddress; //Physical address of this descriptor
union{
POHCD_TRANSFER_DESCRIPTOR NextFree; //Used when the block is on the free list.
POHCD_ENDPOINT Endpoint; //Endpoint which executed this transfer
};
PURB Urb; //Urb we are connected to
UCHAR Flags; //Various flags
UCHAR Bytes; //Various flags
UCHAR Type; //Type of TD
UCHAR HostControllerNumber; //0xFF when not in use.
} OHCD_TRANSFER_DESCRIPTOR;
#define OHCD_TD_FLAG_CANCEL_PENDING 0x00000001 //TD has been marked for cancel
#define OHCD_TD_FLAG_LAST_TD 0x00000002 //Last TD of an URB
#define OHCD_TD_TYPE_DATA 0 //Setup TD of control transfer
#define OHCD_TD_TYPE_SETUP 1 //Setup TD of control transfer
#define OHCD_TD_TYPE_STATUS 2 //Status TD of control transfer
#define OHCD_TD_TYPE_DUMMY 3 //Dummy TD of control transfer
//
// Flags used for the HcdUrbFlags found in the HCD area
// of asynchronous transfer URBS. These flags are used
// for tracking the state of an URB so that it can be
// cancelled.
//
#define OHCD_URB_FLAG_CANCELED 0x0001
#define OHCD_URB_FLAG_QUEUED 0x0002
#define OHCD_URB_FLAG_PROGRAMMED 0x0004
#define OHCD_URB_FLAG_COMPLETED 0x0008
// Flags for isoch use are defined in isoch.h
// This mask just claims the bits.
#define OHCD_URB_FLAG_ISOCH_USE 0x0F00
//
// struct OHCD_SETUP_STATUS_BUFFER
//
// This structure is used for control transfers
// to hold the setup packet data. We define it as a type of
// descriptor block so that we can leverage
// the same code used for EDs and TDs
//
typedef struct _OHCD_SETUP_BUFFER
{
UCHAR Setup[8]; //Holds the data for a setup packet
ULONG Pad1[2]; //Padding to keep the structure the correct size
//
// Standard driver dependent part of block
//
ULONG PhysicalAddress; //Physical address of this block
ULONG Pad2[3]; //Pad to 32 bytes
} OHCD_SETUP_BUFFER;
//
// Interrupt Node - see schedule.c for overview
//
typedef struct _OHCD_INTERRUPT_SCHEDULE_NODE
{
BOOLEAN RegisterHead;
UCHAR Pad;
USHORT Bandwidth;
USHORT BandwidthChildren;
USHORT BandwidthParents;
POHCD_ENDPOINT EndpointHead;
POHCD_ENDPOINT EndpointTail;
} OHCD_INTERRUPT_SCHEDULE_NODE;
//
// Endpoint schedule - see schedule.c for overview
//
typedef struct _OHCD_ENDPOINT_SCHEDULE
{
OHCD_INTERRUPT_SCHEDULE_NODE InterruptSchedule[64];
POHCD_ENDPOINT ControlHead;
POHCD_ENDPOINT BulkHead;
USHORT BandwidthPeriodic;
USHORT BandwidthTotal;
} OHCD_ENDPOINT_SCHEDULE;
//
// Endpoint. Due to the first member this structure must start on a 16-byte boundary.
//
typedef struct _OHCD_ENDPOINT
{
//
// OHCI mandated portion of endpoint. This structure
// must start on a paragraph(16-byte) boundary.
//
OHCI_ENDPOINT_DESCRIPTOR HcEndpointDescriptor;
//
// Fields for managing the schedule (especially for interrupt)
//
UCHAR Flags; //Endpoint flags
UCHAR EndpointType; //Type of endpoint
UCHAR ScheduleIndex; //Index in schedule - see definitions above
UCHAR PollingInterval; //Maximum polling interval (in ms)
ULONG PhysicalAddress; //Physical address of this structure.
POHCD_ENDPOINT Next; //Next endpoint in schedule
ULONG PauseFrame; //Used to verify that we have waited at least
UCHAR PendingPauseCount; //Number of reasons that we are paused.
UCHAR Padding; //Padding to keep up DWORD alignement.
USHORT Bandwidth; //Bandwidth required by this endpoint (interrupt and isoch only)
USHORT TDInUseCount; //Count of TDs in use.
UCHAR QueuedUrbCount; //Count of URBs that are queued waiting to be programmed.
UCHAR ProgrammedUrbCount; //Count URBs that are currently programmed.
//
// Fields for managing URBs and keeping track of transfers
//
PURB PendingUrbHeadP;
PURB PendingUrbTailP;
} OHCD_ENDPOINT;
#define OHCD_ENDPOINT_FLAG_CLOSING 0x10 //Flag used to indicate that endpoint is being
//closed, block cancels when endpoint is closing
#define OHCD_ENDPOINT_FLAG_PAUSING 0x20 //Flag used so that we don't try
//to pause the endpoint twice.
#define OHCD_ENDPOINT_FLAG_DELAY_PAUSE 0x40 //Indicates that the endpoint should not be considered
//paused until the next interrupt, set by the pause
//routine if a DPC was already queued.
typedef struct _OHCD_ROOT_HUB_OBJECT
{
UCHAR NumberOfPorts; //Number of ports present on the root hub.
UCHAR DeviceDetectedBitmap; //Bitmap of ports which have a detected device
LARGE_INTEGER PowerOnToGoodTime; //PowerOnToGoodTime in relative 100ns intervals
PFNHCD_RESET_COMPLETE ResetComplete; //Completion Routine.
PVOID ResetContext; //Completion Context.
KTIMER ResetTimeoutTimer; //Timer in case reset times out.
KDPC ResetTimeoutDPC; //DPC to be called if reset time-out occurs.
} OHCD_ROOT_HUB_OBJECT, *POHCD_ROOT_HUB_OBJECT;
VOID
HCD_ResetRootHubPort(
IN PVOID HcdDeviceExtension,
IN ULONG PortNumber,
IN PFNHCD_RESET_COMPLETE ResetCompleteProc,
IN PVOID CompleteContext
);
typedef struct _OHCD_DEVICE_EXTENSION
{
POHCI_OPERATIONAL_REGISTERS OperationalRegisters; //Port address of operational registers
ULONG OperationalRegistersLength; //May vary depending on downstream port count
POHCI_HCCA HCCA; //HCD accessable pointer to HCCA
OHCD_ENDPOINT_SCHEDULE Schedule; //Everything we need to know about the schedule
ULONG FrameHighPart; //The high part of a 32-bit frame counter.
//The hardware only keeps 16 bits.
PURB ControlUrbHeadP; //Head of URBs for control transfers
PURB ControlUrbTailP; //Tail of URBs for control transfers
PURB BulkUrbHeadP; //Head of URBs for bulk transfers
PURB BulkUrbTailP; //Tail of URBs for bulk transfers
PURB PendingCancels; //URBs that need to be canceled.
PURB PendingAborts; //URBs that need to be aborted.
PURB PendingCloses; //URBs representing pending closes.
struct
{ /* A context structure between Isr and Dpc */
ULONG InterruptsSignaled; //Bit field of interrupt conditions signaled
ULONG Frame; //The frame number when the interrupt occured
} IsrDpc_Context;
KDPC IsrDpc; //DPC for the ISR
ULONG HostControllerNumber; //Host Controller Number - really only a byte
OHCD_ROOT_HUB_OBJECT RootHubObject; //Everything the root hub needs to know
HAL_SHUTDOWN_REGISTRATION ShutdownRegistration;
} OHCD_DEVICE_EXTENSION;
//
// WorkItem Payload for Hotplug items.
//
typedef struct _OHCD_PORT_INFO
{
USHORT PortsConnectionChanged; //Bitfield of ports whose connection status needs updating
USHORT PortsConnected; //Bitfield of ports that now show connected status
} OHCD_PORT_INFO, *POHCD_PORT_INFO;
//---------------------------------------------------------------------------------------------------------------
// Choose max controller based on the number of controllers
//---------------------------------------------------------------------------------------------------------------
#define HCD_MAX_HOST_CONTROLLERS 1
#if (USB_HOST_CONTROLLER_CONFIGURATION!=USB_SINGLE_HOST_CONTROLLER)
#undef HCD_MAX_HOST_CONTROLLERS
#define HCD_MAX_HOST_CONTROLLERS 2
#endif
//------------------------------------------------------
// Pull in Isochronous Support (or stubs)
//------------------------------------------------------
#include "isoch.h"
//------------------------------------------------------
// Implemented in OHCD.C
//------------------------------------------------------
VOID
FASTCALL
OHCD_fPauseEndpoint(
POHCD_DEVICE_EXTENSION DeviceExtension,
POHCD_ENDPOINT endpoint
);
//--------------------------------------------------------
// Implemented in Schedule.c
//--------------------------------------------------------
VOID
FASTCALL
OHCD_ScheduleInitialize(
IN POHCD_DEVICE_EXTENSION DeviceExtension
);
USBD_STATUS
FASTCALL
OHCD_ScheduleAddEndpointPeriodic(
IN POHCD_DEVICE_EXTENSION DeviceExtension,
IN POHCD_ENDPOINT Endpoint
);
VOID
FASTCALL
OHCD_ScheduleRemoveEndpointPeriodic(
IN POHCD_DEVICE_EXTENSION DeviceExtension,
IN POHCD_ENDPOINT Endpoint
);
VOID
FASTCALL
OHCD_ScheduleAddEndpointControlOrBulk(
IN POHCD_DEVICE_EXTENSION DeviceExtension,
IN POHCD_ENDPOINT Endpoint
);
VOID
FASTCALL
OHCD_ScheduleRemoveEndpointControlOrBulk(
IN POHCD_DEVICE_EXTENSION DeviceExtension,
IN POHCD_ENDPOINT Endpoint
);
//------------------------------------------------------------
// Implemented in Isr.c
//------------------------------------------------------------
BOOLEAN
OHCD_InterruptService(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext
);
VOID
OHCD_IsrDpc(
PKDPC Dpc,
PVOID DeviceExtensionPtr,
PVOID Bogus1,
PVOID Bogus2
);
ULONG
FASTCALL
OHCD_Get32BitFrameNumber(
IN POHCD_DEVICE_EXTENSION DeviceExtension
);
//------------------------------------------------------------
// Implemented in transfer.c
//------------------------------------------------------------
USBD_STATUS
FASTCALL
OHCD_fQueueTransferRequest(
POHCD_DEVICE_EXTENSION DeviceExtension,
PURB HcdUrb
);
VOID
FASTCALL
OHCD_fProgramInterruptTransfer(
POHCD_DEVICE_EXTENSION DeviceExtension,
POHCD_ENDPOINT Endpoint
);
VOID
FASTCALL
OHCD_fProgramBulkTransfer(
POHCD_DEVICE_EXTENSION DeviceExtension
);
VOID
FASTCALL
OHCD_fProgramControlTransfer(
POHCD_DEVICE_EXTENSION DeviceExtension
);
//------------------------------------------------------------
// Implemented in roothub.c
//------------------------------------------------------------
VOID
FASTCALL
OHCD_RootHubInitialize(
POHCD_DEVICE_EXTENSION DeviceExtension
);
VOID
FASTCALL
OHCD_RootHubProcessInterrupt(
POHCD_DEVICE_EXTENSION DeviceExtension
);
VOID
FASTCALL
OHCD_RootHubProcessHotPlug(
IN POHCD_DEVICE_EXTENSION DeviceExtension,
IN POHCD_PORT_INFO PortInfo
);
//------------------------------------------------------
// Implemented in pool.c
//------------------------------------------------------
//
// struct OHCD_POOL - Global structure pool for
// all DMA managed structures
//
typedef struct _OHCD_POOL
{
ULONG VirtualToPhysical;
POHCI_HCCA Hcca[HCD_MAX_HOST_CONTROLLERS];
POHCD_ENDPOINT FreeEndpoints;
POHCD_TRANSFER_DESCRIPTOR FreeTDs;
POHCD_TRANSFER_DESCRIPTOR FirstTD; //First TD in pool
POHCD_TRANSFER_DESCRIPTOR LastTD; //Last TD in pool
ULONG LostDoneHeadCount; //Number of times the DoneHead was lost.
ULONG LostMinimumDoneListLength; //minimum length of the DoneHead when
//it was lost
USHORT ControlQuota;
USHORT ControlQuotaRemaining;
USHORT BulkQuota;
USHORT BulkQuotaRemaining;
OHCD_ISOCH_POOL
} OHCD_POOL;
extern OHCD_POOL OHCD_GlobalPool;
#define OHCD_INTERRUPT_TD_QUOTA 3 //Per endpoint quota
VOID
FASTCALL
OHCD_fPoolInit(
IN PHCD_RESOURCE_REQUIREMENTS pResourceRequirements
);
#ifdef SILVER
ULONG
FASTCALL
OHCD_fPoolFindLostDoneHead(
POHCD_DEVICE_EXTENSION DeviceExtension
);
#endif //SILVER
__inline
POHCI_HCCA
OHCD_PoolGetHcca(
IN UCHAR HostControllerNumber
)
{
ASSERT(HCD_MAX_HOST_CONTROLLERS > HostControllerNumber);
return OHCD_GlobalPool.Hcca[HostControllerNumber];
}
__inline
POHCD_ENDPOINT
OHCD_PoolAllocateEndpoint()
{
POHCD_ENDPOINT retVal;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
retVal = OHCD_GlobalPool.FreeEndpoints;
if(retVal)
{
OHCD_GlobalPool.FreeEndpoints = retVal->Next;
}
ASSERT(retVal);
return retVal;
}
__inline
VOID
OHCD_PoolFreeEndpoint(POHCD_ENDPOINT Endpoint)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
Endpoint->Next = OHCD_GlobalPool.FreeEndpoints;
OHCD_GlobalPool.FreeEndpoints = Endpoint;
}
__inline
POHCD_TRANSFER_DESCRIPTOR
OHCD_PoolAllocateTD(UCHAR HostControllerNumber)
{
POHCD_TRANSFER_DESCRIPTOR retVal;
retVal = OHCD_GlobalPool.FreeTDs;
if(retVal)
{
OHCD_GlobalPool.FreeTDs = retVal->NextFree;
}
ASSERT(retVal);
retVal->HostControllerNumber = HostControllerNumber;
OHCD_CLEAR_TD_ISOCH_FORMAT_BIT(retVal);
return retVal;
}
__inline
VOID
OHCD_PoolFreeTD(
IN POHCD_TRANSFER_DESCRIPTOR TransferDescriptor
)
{
// We want the hardware NextTD to be an invalid
// non-NULL address. This aids in searching for
// lost TD lists.
TransferDescriptor->HcTransferDescriptor.NextTD = 0xFFFFFFFF;
TransferDescriptor->HostControllerNumber = 0xFF;
TransferDescriptor->NextFree = OHCD_GlobalPool.FreeTDs;
OHCD_GlobalPool.FreeTDs = TransferDescriptor;
}
__inline
POHCD_TRANSFER_DESCRIPTOR
OHCD_PoolTDFromPhysicalAddress(
IN ULONG PhysicalAddress
)
{
return (POHCD_TRANSFER_DESCRIPTOR)(OHCD_GlobalPool.VirtualToPhysical + PhysicalAddress);
}
__inline
ULONG
OHCD_PoolGetPhysicalAddress(PVOID VirtualAddress)
{
return ((ULONG)VirtualAddress) - OHCD_GlobalPool.VirtualToPhysical;
}
__inline
USHORT
OHCD_PoolGetControlQuota()
{ return OHCD_GlobalPool.ControlQuota; }
__inline
BOOLEAN
OHCD_PoolDebitControlTDQuota(
IN USHORT Count
)
{
return
(OHCD_GlobalPool.ControlQuotaRemaining < Count) ?
FALSE :
(OHCD_GlobalPool.ControlQuotaRemaining -= Count, TRUE);
}
__inline
VOID
OHCD_PoolCreditControlTDQuota(
IN USHORT Count
)
{
OHCD_GlobalPool.ControlQuotaRemaining += Count;
}
__inline
USHORT
OHCD_PoolGetBulkQuota()
{ return OHCD_GlobalPool.BulkQuota; }
__inline
BOOLEAN
OHCD_PoolDebitBulkTDQuota(
IN USHORT Count
)
{
return
(OHCD_GlobalPool.BulkQuotaRemaining < Count) ?
FALSE :
(OHCD_GlobalPool.BulkQuotaRemaining -= Count, TRUE);
}
__inline
VOID
OHCD_PoolCreditBulkTDQuota(
IN USHORT Count
)
{
OHCD_GlobalPool.BulkQuotaRemaining += Count;
}
#ifdef DVTSNOOPBUG
VOID OHCD_PoolCreateDoubleBufferPool();
VOID OHCD_PoolStartDoubleBufferTransfer(PURB Urb);
VOID OHCD_PoolEndDoubleBufferTransfer(PURB Urb);
#endif
//Isoch routines are conditionally compiled
#ifdef OHCD_ISOCHRONOUS_SUPPORTED
__inline
ULONG_PTR
OHCD_IsochPoolAllocateEndpoint()
{
ULONG_PTR retVal;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
retVal = OHCD_GlobalPool.IsochFreeEndpoints;
if(retVal)
{
OHCD_GlobalPool.IsochFreeEndpoints = *((PULONG_PTR)retVal);
}
ASSERT(retVal);
return retVal;
}
__inline
VOID
OHCD_IsochPoolFreeEndpoint(ULONG_PTR IsochEndpoint)
{
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
*((PULONG_PTR)IsochEndpoint) = OHCD_GlobalPool.IsochFreeEndpoints;
OHCD_GlobalPool.IsochFreeEndpoints = IsochEndpoint;
}
__inline
ULONG OHCD_IsochPoolGetMaxBuffers()
{
return OHCD_GlobalPool.IsochMaxBuffers;
}
#endif //OHCD_ISOCHRONOUS_SUPPORTED
#endif __OCHD_H__