/*
* Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.

* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA 
*/

//******************************************************************************
//*     This file contains SWAPSiFs
//******************************************************************************



#include "vsa2.h"
#include "protos.h"
#include "chipset.h"
#include "legacy.h"
#include "pci.h"


// External variables
extern Hardware SystemInfo;

// Local variables
ULONG OHCI_Address[2];
UCHAR WinCE_Flag = 1;


//*****************************************************************
// Fixes 118.438 - OHCI May Not Recognize Device Attach/Removal
//*****************************************************************
void pascal OHCI_SWAPSiF(UCHAR Flag)
{ PRIORITY Priority = 0;
  static PRIORITY LastPriority = 0x5555;

  switch (SystemInfo.Chipset_ID) {
    case DEVICE_ID_5536:
      break;

    default:
      if (Flag == 0) {
        Priority = UNREGISTER_PRIORITY;
      }
      if (Priority != LastPriority) {
        LastPriority = Priority;
        SYS_REGISTER_EVENT(EVENT_TIMER, USBF_PERIOD, USBF_HANDLE, Priority);
      }
      break;
  }
}


#define HcControl 0x0004
  #define HCFS				0x000000C0L
  #define USB_RESET			0x00000000L
  #define USB_RESUME		0x00000040L
  #define USB_OPERATIONAL	0x00000080L
  #define USB_SUSPEND	 	0x000000C0L
  #define IR				0x00000100L
#define HceControl 0x0100

//***********************************************************************
void Do_OHCI_SWAPSif(void)
{ ULONG i, PCI_Addr, HC_Addr, OldValue;

  for (i=0; i<=1; i++) {

    // Get base of Host Controller's registers
    HC_Addr = OHCI_Address[i];

    // Ignore this tick if BAR is being sized
    if (HC_Addr == 0xFFFFF000 || HC_Addr == 0x00000000) {
      continue;
    }

    // Check if Host Controller registers are accessible
    PCI_Addr = 0x80007C00L + (i<<8);
    if (READ_PCI_BYTE(PCI_Addr + COMMAND) & MEM_SPACE) {

      OldValue = READ_MEMORY(HC_Addr + HcControl);

      // WinCE doesn't perform a valid Ownership Change.
      // It disables MIE then performs the Ownership Change request.
      // This code detects that situation and turns emulation off.
      // Otherwise, neither the USB keyboard or PS/2 keyboard works.
      if ((i == 0) && (OldValue & IR) == 0 && WinCE_Flag) {
        WinCE_Flag = 0;   // Only do this once
        WRITE_MEMORY(HC_Addr + HceControl, 0x00);
      }

      // Transition through Operational to clear possible attach/detach glitch
      if ((OldValue & USB_SUSPEND) == USB_SUSPEND) {
        WRITE_MEMORY(HC_Addr + HcControl, USB_OPERATIONAL);
        WRITE_MEMORY(HC_Addr + HcControl, OldValue);
      }
    }
  }
}



//***********************************************************************
// Initialization for the OHCI attach/detach hardware bug
//***********************************************************************
void Init_OHCI_SWAPSiF(UCHAR InitStage)
{
  switch (InitStage) {
    case EARLY_INIT:
      // Trap writes to SB F4 & F5 BAR0 in order keep current OHCI BAR values
      SYS_REGISTER_EVENT(EVENT_PCI_TRAP, 0x7C10, WRITES_ONLY | 0x100, 0);
      break;

    case END_OF_POST_INIT:
      // Turn on the timer
      OHCI_SWAPSiF(1);
      break;
  }
}