/** @file
Private Header file for Usb Host Controller PEIM

Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>

SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef _EFI_EHCI_URB_H_
#define _EFI_EHCI_URB_H_

typedef struct _PEI_EHC_QTD PEI_EHC_QTD;
typedef struct _PEI_EHC_QH  PEI_EHC_QH;
typedef struct _PEI_URB     PEI_URB;

#define EHC_CTRL_TRANSFER       0x01
#define EHC_BULK_TRANSFER       0x02
#define EHC_INT_TRANSFER_SYNC   0x04
#define EHC_INT_TRANSFER_ASYNC  0x08

#define EHC_QTD_SIG             SIGNATURE_32 ('U', 'S', 'B', 'T')
#define EHC_QH_SIG              SIGNATURE_32 ('U', 'S', 'B', 'H')
#define EHC_URB_SIG             SIGNATURE_32 ('U', 'S', 'B', 'R')

//
// Hardware related bit definitions
//
#define EHC_TYPE_ITD            0x00
#define EHC_TYPE_QH             0x02
#define EHC_TYPE_SITD           0x04
#define EHC_TYPE_FSTN           0x06

#define QH_NAK_RELOAD           3
#define QH_HSHBW_MULTI          1

#define QTD_MAX_ERR             3
#define QTD_PID_OUTPUT          0x00
#define QTD_PID_INPUT           0x01
#define QTD_PID_SETUP           0x02

#define QTD_STAT_DO_OUT         0
#define QTD_STAT_DO_SS          0
#define QTD_STAT_DO_PING        0x01
#define QTD_STAT_DO_CS          0x02
#define QTD_STAT_TRANS_ERR      0x08
#define QTD_STAT_BABBLE_ERR     0x10
#define QTD_STAT_BUFF_ERR       0x20
#define QTD_STAT_HALTED         0x40
#define QTD_STAT_ACTIVE         0x80
#define QTD_STAT_ERR_MASK       (QTD_STAT_TRANS_ERR | QTD_STAT_BABBLE_ERR | QTD_STAT_BUFF_ERR)

#define QTD_MAX_BUFFER          4
#define QTD_BUF_LEN             4096
#define QTD_BUF_MASK            0x0FFF

#define QH_MICROFRAME_0         0x01
#define QH_MICROFRAME_1         0x02
#define QH_MICROFRAME_2         0x04
#define QH_MICROFRAME_3         0x08
#define QH_MICROFRAME_4         0x10
#define QH_MICROFRAME_5         0x20
#define QH_MICROFRAME_6         0x40
#define QH_MICROFRAME_7         0x80

#define USB_ERR_SHORT_PACKET    0x200

//
// Fill in the hardware link point: pass in a EHC_QH/QH_HW
// pointer to QH_LINK; A EHC_QTD/QTD_HW pointer to QTD_LINK
//
#define QH_LINK(Addr, Type, Term) \
          ((UINT32) ((EHC_LOW_32BIT (Addr) & 0xFFFFFFE0) | (Type) | ((Term) ? 1 : 0)))

#define QTD_LINK(Addr, Term)      QH_LINK((Addr), 0, (Term))

//
// The defination of EHCI hardware used data structure for
// little endian architecture. The QTD and QH structures
// are required to be 32 bytes aligned. Don't add members
// to the head of the associated software strucuture.
//
#pragma pack(1)
typedef struct {
  UINT32                  NextQtd;
  UINT32                  AltNext;

  UINT32                  Status       : 8;
  UINT32                  Pid          : 2;
  UINT32                  ErrCnt       : 2;
  UINT32                  CurPage      : 3;
  UINT32                  Ioc          : 1;
  UINT32                  TotalBytes   : 15;
  UINT32                  DataToggle   : 1;

  UINT32                  Page[5];
  UINT32                  PageHigh[5];
} QTD_HW;

typedef struct {
  UINT32                  HorizonLink;
  //
  // Endpoint capabilities/Characteristics DWord 1 and DWord 2
  //
  UINT32                  DeviceAddr   : 7;
  UINT32                  Inactive     : 1;
  UINT32                  EpNum        : 4;
  UINT32                  EpSpeed      : 2;
  UINT32                  DtCtrl       : 1;
  UINT32                  ReclaimHead  : 1;
  UINT32                  MaxPacketLen : 11;
  UINT32                  CtrlEp       : 1;
  UINT32                  NakReload    : 4;

  UINT32                  SMask        : 8;
  UINT32                  CMask        : 8;
  UINT32                  HubAddr      : 7;
  UINT32                  PortNum      : 7;
  UINT32                  Multiplier   : 2;

  //
  // Transaction execution overlay area
  //
  UINT32                  CurQtd;
  UINT32                  NextQtd;
  UINT32                  AltQtd;

  UINT32                  Status       : 8;
  UINT32                  Pid          : 2;
  UINT32                  ErrCnt       : 2;
  UINT32                  CurPage      : 3;
  UINT32                  Ioc          : 1;
  UINT32                  TotalBytes   : 15;
  UINT32                  DataToggle   : 1;

  UINT32                  Page[5];
  UINT32                  PageHigh[5];
} QH_HW;
#pragma pack()


//
// Endpoint address and its capabilities
//
typedef struct _USB_ENDPOINT {
  UINT8                   DevAddr;
  UINT8                   EpAddr;     // Endpoint address, no direction encoded in
  EFI_USB_DATA_DIRECTION  Direction;
  UINT8                   DevSpeed;
  UINTN                   MaxPacket;
  UINT8                   HubAddr;
  UINT8                   HubPort;
  UINT8                   Toggle;     // Data toggle, not used for control transfer
  UINTN                   Type;
  UINTN                   PollRate;   // Polling interval used by EHCI
} USB_ENDPOINT;

//
// Software QTD strcture, this is used to manage all the
// QTD generated from a URB. Don't add fields before QtdHw.
//
struct _PEI_EHC_QTD {
  QTD_HW                  QtdHw;
  UINT32                  Signature;
  EFI_LIST_ENTRY          QtdList;   // The list of QTDs to one end point
  UINT8                   *Data;     // Buffer of the original data
  UINTN                   DataLen;   // Original amount of data in this QTD
};



//
// Software QH structure. All three different transaction types
// supported by UEFI USB, that is the control/bulk/interrupt
// transfers use the queue head and queue token strcuture.
//
// Interrupt QHs are linked to periodic frame list in the reversed
// 2^N tree. Each interrupt QH is linked to the list starting at
// frame 0. There is a dummy interrupt QH linked to each frame as
// a sentinental whose polling interval is 1. Synchronous interrupt
// transfer is linked after this dummy QH.
//
// For control/bulk transfer, only synchronous (in the sense of UEFI)
// transfer is supported. A dummy QH is linked to EHCI AsyncListAddr
// as the reclamation header. New transfer is inserted after this QH.
//
struct _PEI_EHC_QH {
  QH_HW                   QhHw;
  UINT32                  Signature;
  PEI_EHC_QH              *NextQh;    // The queue head pointed to by horizontal link
  EFI_LIST_ENTRY          Qtds;       // The list of QTDs to this queue head
  UINTN                   Interval;
};

//
// URB (Usb Request Block) contains information for all kinds of
// usb requests.
//
struct _PEI_URB {
  UINT32                          Signature;
  EFI_LIST_ENTRY                  UrbList;

  //
  // Transaction information
  //
  USB_ENDPOINT                    Ep;
  EFI_USB_DEVICE_REQUEST          *Request;     // Control transfer only
  VOID                            *RequestPhy;  // Address of the mapped request
  VOID                            *RequestMap;
  VOID                            *Data;
  UINTN                           DataLen;
  VOID                            *DataPhy;     // Address of the mapped user data
  VOID                            *DataMap;
  EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
  VOID                            *Context;

  //
  // Schedule data
  //
  PEI_EHC_QH                      *Qh;

  //
  // Transaction result
  //
  UINT32                          Result;
  UINTN                           Completed;    // completed data length
  UINT8                           DataToggle;
};

/**
  Delete a single asynchronous interrupt transfer for
  the device and endpoint.

  @param  Ehc         The EHCI device.
  @param  Data        Current data not associated with a QTD.
  @param  DataLen     The length of the data.
  @param  PktId       Packet ID to use in the QTD.
  @param  Toggle      Data toggle to use in the QTD.
  @param  MaxPacket   Maximu packet length of the endpoint.

  @retval the pointer to the created QTD or NULL if failed to create one.

**/
PEI_EHC_QTD *
EhcCreateQtd (
  IN PEI_USB2_HC_DEV      *Ehc,
  IN UINT8                *Data,
  IN UINTN                DataLen,
  IN UINT8                PktId,
  IN UINT8                Toggle,
  IN UINTN                MaxPacket
  )
;

/**
  Allocate and initialize a EHCI queue head.

  @param  Ehci      The EHCI device.
  @param  Ep        The endpoint to create queue head for.

  @retval the pointer to the created queue head or NULL if failed to create one.

**/
PEI_EHC_QH *
EhcCreateQh (
  IN PEI_USB2_HC_DEV      *Ehci,
  IN USB_ENDPOINT         *Ep
  )
;

/**
  Free an allocated URB. It is possible for it to be partially inited.

  @param  Ehc         The EHCI device.
  @param  Urb         The URB to free.

**/
VOID
EhcFreeUrb (
  IN PEI_USB2_HC_DEV      *Ehc,
  IN PEI_URB              *Urb
  )
;

/**
  Create a new URB and its associated QTD.

  @param  Ehc               The EHCI device.
  @param  DevAddr           The device address.
  @param  EpAddr            Endpoint addrress & its direction.
  @param  DevSpeed          The device speed.
  @param  Toggle            Initial data toggle to use.
  @param  MaxPacket         The max packet length of the endpoint.
  @param  Hub               The transaction translator to use.
  @param  Type              The transaction type.
  @param  Request           The standard USB request for control transfer.
  @param  Data              The user data to transfer.
  @param  DataLen           The length of data buffer.
  @param  Callback          The function to call when data is transferred.
  @param  Context           The context to the callback.
  @param  Interval          The interval for interrupt transfer.

  @retval the pointer to the created URB or NULL.

**/
PEI_URB *
EhcCreateUrb (
  IN PEI_USB2_HC_DEV                    *Ehc,
  IN UINT8                              DevAddr,
  IN UINT8                              EpAddr,
  IN UINT8                              DevSpeed,
  IN UINT8                              Toggle,
  IN UINTN                              MaxPacket,
  IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Hub,
  IN UINTN                              Type,
  IN EFI_USB_DEVICE_REQUEST             *Request,
  IN VOID                               *Data,
  IN UINTN                              DataLen,
  IN EFI_ASYNC_USB_TRANSFER_CALLBACK    Callback,
  IN VOID                               *Context,
  IN UINTN                              Interval
  )
;
#endif
