// **********************************************************************
// * serpci.c                                                           *
// *                                                                    *
// * Written by Matthew DeLoera (deloera@us.ibm.com)                    *
// * (C) Copyright IBM Corporation, 1998-2001                           *
// *                                                                    *
// *  This software may be used and distributed according to the terms  *
// *  of the GNU Public License, incorporated herein by reference.      *
// **********************************************************************

// **********************************************************************
// * serpci.c - This source file provides all PCI-specific functionality*
// *            such as hardware detection and UART register access.    *
// *                                                                    *
// * Changes                                                            *
// * -------                                                            *
// * 02/12/2001 - Cleaned up for open source release.                   *
// **********************************************************************


#include <linux/autoconf.h>
#ifdef CONFIG_SMP
     #define __SMP__
#endif
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
     #define MODVERSIONS
#endif
#ifdef MODVERSIONS
     #include <linux/modversions.h>
#endif
#include <linux/types.h>
#include <linux/fs.h>     /* for fops structure */
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/serial_reg.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#ifndef LINUX_VERSION_CODE
     #include <linux/version.h>
#endif


// USED BY sysscout.h
unsigned char READ_REGISTER_UCHAR(unsigned char *x)
{
     unsigned char tempuchar;
     memcpy(&tempuchar, x, sizeof(unsigned char));
     return tempuchar;
}


// USED BY sysscout.h
void WRITE_REGISTER_UCHAR(unsigned char *x, unsigned char y)
{
     unsigned char tempuchar = y;
     memcpy(x, &tempuchar, sizeof(unsigned char));
     return;
}

// Start of PHR_180930
// USED BY sysscout.h
u32 READ_REGISTER_ULONG(void *x)
{
     u32 tempulong;
     tempulong = readl(x);
     return tempulong;
}

// USED BY sysscout.h
void WRITE_REGISTER_ULONG(unsigned long *x, u32 y)
{
     u32 tempulong;
     tempulong = y;
     writel(tempulong, x);
     return;
}

/*
void WRITE_REGISTER_ULONG(unsigned long *x, unsigned long y)
{
     unsigned long tempulong;
     tempulong = y;
     memcpy(x, &tempulong, sizeof(unsigned long));
     return;
}

unsigned long READ_REGISTER_ULONG(void *x)
{
     unsigned long tempulong;
     memcpy(&tempulong, x, sizeof(unsigned long));
     return tempulong;
}

*/
// End of PHR_180930

#include "sysscout.h"

// **********************
// * USER-DEFINED TYPES *
// **********************

typedef unsigned char  UCHAR;
typedef unsigned short USHORT;
typedef u_int32_t      ULONG;     // PHR_180930 
typedef u_long        *PULONG;

//typedef unsigned long  ULONG;     // PHR_180930  

#define PLX9080_VENDORID      0x1014 // IBM==0x1014
#define PLX9080_DEVICEID      0x00DC // Wiseman


// ********************
// * EXPORTED GLOBALS *
// ********************

unsigned short  IBMirq  = 0;
unsigned short  IBMport = 0;
UCHAR          *IBMbase = NULL;



extern unsigned char  IBMASMibmasmexists;
extern unsigned char  IBMASMwisemanexists;
extern unsigned char  IBMASMeagleexists;
extern unsigned short IBMASMirq;
extern unsigned char  *IBMASMeaglebase;
extern unsigned short IBMASMwisemanport;
extern unsigned short IBMASMwisemanbase;


void IBM_GetDeviceInformation(void)
{
     // GET INTERRUPT VECTOR FROM ibmasm
     IBMirq = IBMASMirq;

     // SET UP LOCAL REFERENCE TO MAPPED BASE ADDRESS
     if (IBMASMeagleexists) IBMbase = IBMASMeaglebase;
     else                   IBMport = IBMASMwisemanport;
     return;
}


void IBM_DisableInterrupts(void)
{     
     ULONG  ulPLXreg;

     // IF EAGLE, USE A MACRO
     if (IBMASMeagleexists)
     {
          SCOUT_DISABLE_COM_INTERRUPTS(IBMbase + SCOUT_INT_STATUS_REGISTER);
          return;
     }

     // READ THE PLX INTERRUPT CONTROL/STATUS REGISTER (32 BITS, 0x68 ABOVE PCIBAR1)
     ulPLXreg = inl(IBMASMwisemanbase + 0x68);

     // CLEAR BIT 11 TO DISABLE LOCAL INTERRUPTS, AND WRITE BACK
     outl((ulPLXreg & 0xFFFFF7FF), (IBMASMwisemanbase + 0x68));
     return;
}


void IBM_EnableInterrupts(void)
{
     ULONG  ulPLXreg;

     // IF EAGLE, USE A MACRO
     if (IBMASMeagleexists)
     {
          SCOUT_ENABLE_COM_INTERRUPTS(IBMbase + SCOUT_INT_STATUS_REGISTER);
          return;
     }

     // READ THE PLX INTERRUPT CONTROL/STATUS REGISTER (32 BITS, 0x68 ABOVE PCIBAR1)
     ulPLXreg = inl(IBMASMwisemanbase + 0x68);

     // SET BIT 11 TO ENABLE LOCAL INTERRUPTS, AND WRITE BACK
     outl((ulPLXreg | 0x00000800), (IBMASMwisemanbase + 0x68));
     return;
}


unsigned char IBM_IsSerialInterrupt(void)
{
     ULONG  ulPLXreg, intStatus;

     // IF EAGLE, USE A MACRO
     if (IBMASMeagleexists)
     {
          intStatus = SCOUT_READ_COM_INT_STATUS(IBMbase + SCOUT_INT_STATUS_REGISTER);
          if (!(intStatus & SCOUT_COM_INTR_ENABLE_MASK))
          {
               return 0;
          }
          return 1;
     }

     // READ THE PLX INTERRUPT CONTROL/STATUS REGISTER (32 BITS, 0x68 ABOVE PCIBAR1)
     ulPLXreg = inl(IBMASMwisemanbase + 0x68);

     // DETERMINE WHETHER BIT 15 IS SET (LOCAL INTERRUPT - READ-ONLY REGISTER)
     if (ulPLXreg & 0x00008000) return 1;
     return 0;
}


void IBM_WriteEagleUART(unsigned char offset, unsigned char value)
{
//printk(KERN_CRIT "ibmser: Writing offset 0x%02x with 0x%02x\n", offset, value);
     IBMbase[SCOUT_COM_B_BASE + offset] = value;
     return;
}


unsigned char IBM_ReadEagleUART(unsigned char offset)
{
//printk(KERN_CRIT "ibmser: Reading offset 0x%02x\n", offset);
     return IBMbase[SCOUT_COM_B_BASE + offset];
}


unsigned char IBM_QueryHostFlag(void)
{
   //  if ( IBMASMeagleexists )
   //  {
   //      unsigned char debug_char;
   //      debug_char = (IBM_ReadEagleUART(UART_SCR));
   //      printk(KERN_CRIT "ibmser: IBM_QueryHostFlag read 0x%02x from the scratchpad.\n", debug_char);
   //  }
     
     // QUERY THE VALUE OF THE SCRATCHPAD REGISTER - ASSUMING IT MUST BE EXACTLY 0x01
     if (IBMASMeagleexists)
     {
          if (IBM_ReadEagleUART(UART_SCR) != 0) return 1;
          return 0;
     }
     if (inb(IBMport + UART_SCR) == 1) return 1;
     return 0;
}



