//-------------------------------------------------------------------------
 
// WINNT driver for PCIVME interface from ARW Elektronik, Germany ---------
 
// all around recognition and basic services of VMEMM
 
//
 
// (c) 1999-2004 ARW Elektronik
 
//
 
// this source code is published under GPL (Open Source). You can use, redistrubute and 
 
// modify it unless this header   is not modified or deleted. No warranty is given that 
 
// this software will work like expected.
 
// This product is not authorized for use as critical component in life support systems
 
// wihout the express written approval of ARW Elektronik Germany.
 
//
 
// Please announce changes and hints to ARW Elektronik
 
//
 
// $Log: pcivme_v.c,v $
 
// Revision 1.3  2004/07/24 07:07:26  klaus
 
// Update copyright to 2004
 
//
 
// Revision 1.2  2003/11/15 19:12:51  klaus
 
// Update copyright to 2003
 
//
 
// Revision 1.1.1.1  2003/11/14 23:16:33  klaus
 
// First put into repository
 
//
 
// Revision 1.3  2002/10/27 16:17:48  klaus
 
// Typing bug fixed caused at log addition
 
//
 
// Revision 1.2  2002/10/27 16:11:02  klaus
 
// Added CVS log into header
 
//
 
// what                                            who          when
 
// started                                         AR           02.07.1999
 
// first release 1.0                                                       AR                   17.10.1999
 
// changed resource allocation caused by WIN2000   AR           08.06.2002
 
//
 
 
 
//-------------------------------------------------------------------------
 
// INCLUDES
 
//
 
#include <ntddk.h>
 
#include <pcivme_drv.h>
 
#include <pcivme_v.h>
 
#include <pciif.h>                      // all around the pci interface
 
 
 
#ifndef WORD                            // don't touch include files of WIN95 driver
 
#define WORD USHORT
 
#endif
 
 
 
#ifndef DWORD
 
#define DWORD ULONG
 
#endif
 
 
 
//------------------------------------------------------------------------
 
// PROTOTYPES
 
//
 
 
 
//------------------------------------------------------------------------
 
// GLOBALS
 
//
 
 
 
//------------------------------------------------------------------------
 
// FUNCTIONS
 
//
 
 
 
//------------------------------------------------------------------------
 
// test connection to VMEMM devices without disturbing anything 
 
//
 
NTSTATUS TestConnection(PCIADA *pciada)
 
{
 
        USHORT *pwADRH = (USHORT *)((ULONG)(pciada->pvVirtIfr) + (ULONG)ADRH);
 
        USHORT *pwADRL = (USHORT *)((ULONG)(pciada->pvVirtIfr) + (ULONG)ADRL);
 
        int i;
 
        USHORT wRet;
 
    USHORT wADRHContent;
 
    USHORT wADRLContent;
 
 
 
        
 
        KdPrint(("TestConnection()\n"));
 
        
 
        wADRHContent = READ_REGISTER_USHORT(pwADRH);    // save previous content
 
        wADRLContent = READ_REGISTER_USHORT(pwADRL);
 
 
 
        for (i = 0; i < 10000; i++)
 
        {
 
                WRITE_REGISTER_USHORT(pwADRH, 0x5555);
 
                WRITE_REGISTER_USHORT(pwADRL, 0xAAAA);
 
                wRet = READ_REGISTER_USHORT(pwADRH);
 
                if (wRet != 0x5555) return STATUS_UNSUCCESSFUL;
 
    
 
                WRITE_REGISTER_USHORT(pwADRH, 0xAAAA);
 
                WRITE_REGISTER_USHORT(pwADRL, 0x5555);
 
                wRet = READ_REGISTER_USHORT(pwADRH);
 
                if (wRet != 0xAAAA) return STATUS_UNSUCCESSFUL;
 
 
 
                WRITE_REGISTER_USHORT(pwADRH, 0x0000);
 
                WRITE_REGISTER_USHORT(pwADRL, 0xFFFF);
 
                wRet = READ_REGISTER_USHORT(pwADRH);
 
                if (wRet != 0x0000) return STATUS_UNSUCCESSFUL;
 
 
 
                WRITE_REGISTER_USHORT(pwADRH, 0xFFFF);
 
                WRITE_REGISTER_USHORT(pwADRL, 0x0000);
 
                wRet = READ_REGISTER_USHORT(pwADRH);
 
                if (wRet != 0xFFFF) return STATUS_UNSUCCESSFUL;
 
        }
 
 
 
        WRITE_REGISTER_USHORT(pwADRH, wADRHContent);    // restore previous content
 
        WRITE_REGISTER_USHORT(pwADRL, wADRLContent);
 
 
 
        KdPrint(("TestConnection() OK.\n"));
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// scan VMEMM devices without disturbing anything 
 
//
 
NTSTATUS PCIVMEScanVMEMM(PDEVICE_OBJECT deviceObj)
 
{
 
        int i;
 
        int nPCIADAs = ((DEVICE_EXT*)(deviceObj->DeviceExtension))->nPCIADAs;
 
        PCIADA           *pciada;
 
        USHORT           wCntrl;
 
        USHORT                   wIntCSR;
 
        USHORT                   wVMEMMStatus;
 
 
 
        KdPrint(("PCIVMEScanVMEMM()\n"));
 
 
 
    for (i = 0; i < nPCIADAs; i++)
 
    {
 
                pciada = &((DEVICE_EXT*)(deviceObj->DeviceExtension))->pciada[i];
 
                
 
                wCntrl  = READ_REGISTER_USHORT(pciada->pwCntrl);   // save it for later use
 
        wIntCSR = READ_REGISTER_USHORT(pciada->pwIntCSR);
 
 
 
                WRITE_REGISTER_USHORT(pciada->pwIntCSR, DISABLE_PCIADA_IRQS);
 
                WRITE_REGISTER_USHORT(pciada->pwCntrl, RELEASE_VMEMM);  // open it for test
 
 
 
                if (wCntrl & 0x0800)
 
                {
 
                        if (TestConnection(pciada) == STATUS_SUCCESS)
 
                        {      
 
                                wVMEMMStatus  = READ_REGISTER_USHORT(pciada->pvVirtIfr);
 
 
 
                                pciada->bConnected              = TRUE;
 
 
 
                                // interpret the content
 
                                pciada->bWordMode               = (wVMEMMStatus & FLAG_WORD)   ? TRUE : FALSE;
 
                                pciada->bSysControl             = (wVMEMMStatus & FLAG_SYSCTL) ? TRUE : FALSE;
 
                                pciada->wModuleNumber   = (wVMEMMStatus & MASK_MODNR)   >> 4;
 
                                pciada->wFPGAVersion    = (wVMEMMStatus & MASK_FPGA)    >> 8;
 
                                pciada->wModuleType             = (wVMEMMStatus & MASK_MODTYPE) >> 12;
 
 
 
                                // calculate some heavy used addresses
 
                                pciada->pwCSR                   = (PUSHORT)((ULONG)(pciada->pvVirtIfr) + CSR); 
 
                                pciada->pbModifier              = (PUCHAR) ((ULONG)(pciada->pvVirtIfr) + VICBASE + AMSR);
 
                                pciada->pdwVMEAdr               = (PULONG) ((ULONG)(pciada->pvVirtIfr) + ADRHL);
 
                                pciada->pwIRQStat               = (PUSHORT)((ULONG)(pciada->pvVirtIfr) + VICRES);
 
                                pciada->pbVector                = (PUCHAR) ((ULONG)(pciada->pvVirtIfr) + VECBASE);
 
                                pciada->pvVME                   = (PVOID)  ((ULONG)(pciada->pvVirtIfr) + VMEBASE);
 
 
 
                                KdPrint(("PCIADA %d <-> VMEMM %d\n", i, pciada->wModuleNumber));
 
                        }
 
                        else  
 
                                pciada->wModuleNumber = 0xFFFF;  // not recognized, take it out
 
                }
 
                else
 
                        pciada->wModuleNumber = 0xFFFF;  // not recognized, take it out
 
 
 
                if (pciada->wModuleNumber != 0xFFFF)
 
                  WRITE_REGISTER_USHORT(pciada->pwCntrl,  wCntrl);   // restore state
 
                else
 
                  WRITE_REGISTER_USHORT(pciada->pwCntrl,  INHIBIT_VMEMM);   
 
 
 
                WRITE_REGISTER_USHORT(pciada->pwIntCSR, wIntCSR);    // restore interrupt masks
 
    }
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// deinit all PCIADAs in a passive state 
 
//
 
NTSTATUS PCIVMEDeInitPCIADAs(PDEVICE_OBJECT deviceObj)
 
{
 
        int              i;
 
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)deviceObj->DeviceExtension;
 
        int                              nPCIADAs = pDevExt->nPCIADAs;
 
        PCIADA           *pciada;
 
 
 
        KdPrint(("PCIVMEDeInitPCIADAs()\n"));
 
 
 
        // dis connect the interrupts to service routines
 
        for (i = 0; i < nPCIADAs; i++)
 
        {
 
                pciada = &pDevExt->pciada[i];
 
 
 
                WRITE_REGISTER_USHORT(pciada->pwIntCSR, DISABLE_PCIADA_IRQS);
 
                WRITE_REGISTER_USHORT(pciada->pwCntrl,  INHIBIT_VMEMM);
 
        }
 
 
 
        return STATUS_SUCCESS;
 
}