/*++

Copyright (c) 2013 Minoca Corp. All Rights Reserved

Module Name:

    ehci.h

Abstract:

    This header contains internal definitions for the EHCI USB Host Controller
    driver.

Author:

    Evan Green 18-Mar-2013

--*/

//
// ------------------------------------------------------------------- Includes
//

#include "ehcihw.h"
#include "ehcidbg.h"
#include <minoca/kernel/kdebug.h>
#include <minoca/kernel/kdusb.h>

//
// ---------------------------------------------------------------- Definitions
//

//
// Define the EHCI allocation tag.
//

#define EHCI_ALLOCATION_TAG 0x69636845 // 'ichE'
#define EHCI_BLOCK_ALLOCATION_TAG 0x6C426845 // 'lBhE'

//
// Define the block expansion count for the EHCI transfer and queue block
// allocator. This is defined in number of blocks.
//

#define EHCI_BLOCK_ALLOCATOR_EXPANSION_COUNT 40

//
// Define the required alignment for EHCI transfers and queues.
//

#define EHCI_BLOCK_ALLOCATOR_ALIGNMENT EHCI_LINK_ALIGNMENT

//
// Define the number of levels in the periodic schedule tree.
//

#define EHCI_PERIODIC_SCHEDULE_TREE_DEPTH 8

//
// Define the set of flags for the EHCI transfer set.
//

#define EHCI_TRANSFER_SET_FLAG_QUEUED     0x00000001
#define EHCI_TRANSFER_SET_FLAG_CANCELLING 0x00000002

//
// ------------------------------------------------------ Data Type Definitions
//

typedef struct _EHCI_TRANSFER_SET EHCI_TRANSFER_SET, *PEHCI_TRANSFER_SET;

/*++

Structure Description:

    This structure stores information about an EHCI transfer.

Members:

    GlobalListEntry - Stores pointers to the next and previous transfers in the
        global list of in-flight transfers.

    EndpointListEntry - Stores pointers to the next and previous transfers in
        the endpoint queue.

    Set - Stores a pointer to the transfer set that this transfer is a part of.

    HardwareTransfer - Stores a pointer to the hardware defined transfer
        descriptor.

    PhysicalAddress - Stores the physical address of the hardware transfer
        descriptor.

    TransferLength - Stores the length of the transfer (as the hardware
        decrements the field towards 0).

    LastTransfer - Stores a boolean indicating whether this is the last
        transfer submitted in the set.

--*/

typedef struct _EHCI_TRANSFER {
    LIST_ENTRY GlobalListEntry;
    LIST_ENTRY EndpointListEntry;
    PEHCI_TRANSFER_SET Set;
    PEHCI_TRANSFER_DESCRIPTOR HardwareTransfer;
    PHYSICAL_ADDRESS PhysicalAddress;
    ULONG TransferLength;
    BOOL LastTransfer;
} EHCI_TRANSFER, *PEHCI_TRANSFER;

/*++

Structure Description:

    This structure stores information about an EHCI transfer queue.

Members:

    ListEntry - Stores pointers to the next and previous transfer queue
        attached to the EHCI controller.

    DummyTransfer - Stores a pointer to the current inactive dummy transfer
        that gets left on every queue. This dummy transfer is needed so that
        additional sets of transfers can be added to a queue without race
        conditions. The dummy transfer rotates around as sets of transfers are
        added, as the first transfer in that set becomes the new dummy.

    HardwareQueueHead - Stores a pointer to the hardware defined transfer queue
        head. This is unused for isochronous transfers.

    PhysicalAddress - Stores the physical address of the hardware queue head.

    AsyncOnAdvanceCancel - Stores a boolean indicating whether or not the queue
        is being processed by the "async on advance" interrupt due to
        cancellation (TRUE) or destruction (FALSE).

--*/

typedef struct _EHCI_TRANSFER_QUEUE {
    LIST_ENTRY ListEntry;
    PEHCI_TRANSFER DummyTransfer;
    PEHCI_QUEUE_HEAD HardwareQueueHead;
    PHYSICAL_ADDRESS PhysicalAddress;
    BOOL AsyncOnAdvanceCancel;
} EHCI_TRANSFER_QUEUE, *PEHCI_TRANSFER_QUEUE;

/*++

Structure Description:

    This structure stores information about an EHCI endpoint.

Members:

    ListEntry - Stores pointers to the next and previous endpoints attached to
        the EHCI controller.

    TransferListHead - Stores the head of the list of transfers on this queue.

    Queue - Stores the EHCI transfer queue for this endpoint.

    TransferType - Stores the transfer type of the endpoint.

    Speed - Stores the speed of the device exposing the endpoint.

    MaxPacketSize - Stores the maximum number of bytes that can be moved in a
        packet for this endpoint.

    PollRate - Stores the interrupt poll rate, in (micro)frames.

    EndpointNumber - Stores the endpoint number, as defined by the USB device.

--*/

typedef struct _EHCI_ENDPOINT {
    LIST_ENTRY ListEntry;
    LIST_ENTRY TransferListHead;
    EHCI_TRANSFER_QUEUE Queue;
    USB_TRANSFER_TYPE TransferType;
    USB_DEVICE_SPEED Speed;
    ULONG MaxPacketSize;
    ULONG PollRate;
    UCHAR EndpointNumber;
} EHCI_ENDPOINT, *PEHCI_ENDPOINT;

/*++

Structure Description:

    This structure stores a collection of EHCI transfers that together
    comprise a USB transfer.

Members:

    ListEntry - Stores pointers to the next and previous transfer sets in
        whatever list of transfer sets this set is in (usually the set of
        lists waiting to be processed once the async advance doorbel is rung).

    TransferCount - Stores the number of elements in the transfer array.

    Flags - Stores a bitmask of flags for the transfer set. See
        EHCI_TRANSFER_SET_FLAG_* for definitions.

    UsbTransfer - Stores a pointer to the transfer as defined by the USB core
        library. Several EHCI transfers may constitute and point to a single USB
        transfer.

    Endpoint - Stores a pointer to the endpoint that owns this set of transfers.

    Transfer - Stores an array of pointers to EHCI transfers.

--*/

struct _EHCI_TRANSFER_SET {
    LIST_ENTRY ListEntry;
    ULONG TransferCount;
    ULONG Flags;
    PUSB_TRANSFER_INTERNAL UsbTransfer;
    PEHCI_ENDPOINT Endpoint;
    PEHCI_TRANSFER Transfer[ANYSIZE_ARRAY];
};

/*++

Structure Description:

    This structure stores USB state for an EHCI controller.

Members:

    RegisterBase - Stores the virtual address where the Operational Registers
        are mapped.

    PhysicalBase - Stores the physical address of the base of the registers
        (the base of EHCI itself, not the operational registers).

    PeriodicSchedule - Stores a pointer to the frame list schedule used by the
        controller.

    PeriodicScheduleIoBuffer - Stores a pointer to the I/O buffer containing the
        periodic schedule.

    AsynchronousSchedule - Stores the empty transfer queue that represents the
        head of the asynchronous schedule.

    IsochronousTransferListHead - Stores the list head of all active
        Isochronous transfers in the schedule.

    BlockAllocator - Stores a pointer to the block allocator used to
        allocate all queues and transfers.

    TransferListHead - Stores the global list of active transfers on the
        schedule.

    AsyncOnAdvanceReadyListHead - Stores the list of transfer queues that have
        been removed from the asynchronous schedule and that the host
        controller can no longer reach.

    AsyncOnAdvancePendingListHead - Stores the list of transfer queues that
        have been removed from the asynchronous schedule, but that the host
        controller may still be able to reach.

    QueuesToDestroyListHead - Stores the list of transfer queues that need to
        be destroyed by the destroy queues work item.

    Lock - Stores the lock that protects access to all list entries under this
        controller. It must be a spin lock because it synchronizes with a DPC,
        which cannot block.

    UsbCoreHandle - Stores the handle returned by the USB core that identifies
        this controller.

    CommandRegister - Stores the current state of the USB command register
        (to avoid unnecessary reads).

    PendingStatusBits - Stores the bits in the USB status register that have
        not yet been addressed by the DPC.

    InterruptHandle - Stores the interrupt handle of the connected interrupt.

    InterruptTree - Stores an array of empty transfer queues at each level of
        the periodic schedule tree. Think of each frame in the schedule as a
        leaf node, and each leaf node points at a more common entry, which
        points at an even more common entry, etc. The last entry in this array
        is polled every millisecond, the next last one every 2ms, then every
        4ms, etc.

    DestroyQueuesWorkItem - Stores a pointer to a work item that destroys queue
        heads that have been completely removed from the schedule.

    PortCount - Stores the number of ports on the EHCI host controller.

    EndpointCount - Stores the number of active endpoints in the controller.

    EndpointListHead - Stores the head of the list of endpoints.

    HandoffData - Stores an optional pointer to the kernel debugger handoff
        data.

--*/

typedef struct _EHCI_CONTROLLER {
    PVOID RegisterBase;
    PHYSICAL_ADDRESS PhysicalBase;
    PEHCI_PERIODIC_SCHEDULE PeriodicSchedule;
    PIO_BUFFER PeriodicScheduleIoBuffer;
    EHCI_TRANSFER_QUEUE AsynchronousSchedule;
    LIST_ENTRY IsochronousTransferListHead;
    PBLOCK_ALLOCATOR BlockAllocator;
    LIST_ENTRY TransferListHead;
    LIST_ENTRY AsyncOnAdvanceReadyListHead;
    LIST_ENTRY AsyncOnAdvancePendingListHead;
    LIST_ENTRY QueuesToDestroyListHead;
    KSPIN_LOCK Lock;
    HANDLE UsbCoreHandle;
    ULONG CommandRegister;
    volatile ULONG PendingStatusBits;
    HANDLE InterruptHandle;
    EHCI_TRANSFER_QUEUE InterruptTree[EHCI_PERIODIC_SCHEDULE_TREE_DEPTH];
    PWORK_ITEM DestroyQueuesWorkItem;
    ULONG PortCount;
    ULONG EndpointCount;
    LIST_ENTRY EndpointListHead;
    PEHCI_DEBUG_HANDOFF_DATA HandoffData;
} EHCI_CONTROLLER, *PEHCI_CONTROLLER;

//
// -------------------------------------------------------------------- Globals
//

extern PDRIVER EhciDriver;

//
// -------------------------------------------------------- Function Prototypes
//

PEHCI_CONTROLLER
EhcipInitializeControllerState (
    PVOID OperationalRegisterBase,
    PHYSICAL_ADDRESS RegisterBasePhysical,
    ULONG PortCount,
    PDEBUG_USB_HANDOFF_DATA HandoffData
    );

/*++

Routine Description:

    This routine initializes the state and variables needed to start up an EHCI
    host controller.

Arguments:

    OperationalRegisterBase - Supplies the virtual address of the base of the
        operational registers.

    RegisterBasePhysical - Supplies the physical address of the base of the
        EHCI registers (not the operational registers).

    PortCount - Supplies the number of ports on the EHCI controller.

    HandoffData - Supplies an optional pointer to the debug handoff data if the
        kernel debugger is using this controller.

Return Value:

    Returns a pointer to the EHCI controller state object on success.

    NULL on failure.

--*/

VOID
EhcipDestroyControllerState (
    PEHCI_CONTROLLER Controller
    );

/*++

Routine Description:

    This routine destroys the memory associated with an EHCI controller.

Arguments:

    Controller - Supplies a pointer to the EHCI controller state to release.

Return Value:

    None.

--*/

KSTATUS
EhcipRegisterController (
    PEHCI_CONTROLLER Controller,
    PDEVICE Device
    );

/*++

Routine Description:

    This routine registers the started EHCI controller with the core USB
    library.

Arguments:

    Controller - Supplies a pointer to the EHCI controller state of the
        controller to register.

    Device - Supplies a pointer to the device object.

Return Value:

    Status code.

--*/

VOID
EhcipSetInterruptHandle (
    PEHCI_CONTROLLER Controller,
    HANDLE InterruptHandle
    );

/*++

Routine Description:

    This routine saves the handle of the connected interrupt in the EHCI
    controller.

Arguments:

    Controller - Supplies a pointer to the EHCI controller state.

    InterruptHandle - Supplies the connected interrupt handle.

Return Value:

    None.

--*/

KSTATUS
EhcipResetController (
    PEHCI_CONTROLLER Controller
    );

/*++

Routine Description:

    This routine resets and starts the EHCI controller.

Arguments:

    Controller - Supplies a pointer to the EHCI controller state of the
        controller to reset.

Return Value:

    Status code.

--*/

INTERRUPT_STATUS
EhcipInterruptService (
    PVOID Context
    );

/*++

Routine Description:

    This routine implements the EHCI interrupt service routine.

Arguments:

    Context - Supplies the context pointer given to the system when the
        interrupt was connected. In this case, this points to the EHCI
        controller.

Return Value:

    Interrupt status.

--*/

INTERRUPT_STATUS
EhcipInterruptServiceDpc (
    PVOID Parameter
    );

/*++

Routine Description:

    This routine implements the EHCI dispatch level interrupt service.

Arguments:

    Parameter - Supplies the context, in this case the EHCI controller
        structure.

Return Value:

    None.

--*/

