//-------------------------------------------------------------------------
 
// WINNT driver for PCIVME interface from ARW Elektronik, Germany ---------
 
// the main body of the driver
 
//
 
// (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_drv.c,v $
 
// Revision 1.3  2004/07/24 07:07:26  klaus
 
// Update copyright to 2004
 
//
 
//
 
// what                                            who          when
 
// started                                         AR           15.06.1999
 
// first release 1.0                               AR           17.10.1999
 
// fixed error in PLX9050Bug                       AR           28.02.2000
 
// PLX9050Bugfix bug fixed                         AR           03.03.2000
 
// PCICC32 CAMAC Interface conflict solved         AR           03.03.2000
 
// Version 1.1 released                            AR           03.03.2000
 
// register all used resources, the idle too       AR           25.11.2001
 
// changed resource allocation caused by WIN2000   AR           08.06.2002
 
//
 
 
 
//-------------------------------------------------------------------------
 
// INCLUDES
 
//
 
#include <initguid.h>
 
#include <wdmguid.h>
 
#include <ntddk.h>
 
#include <devioctl.h>
 
#include <pcivme_drv.h>
 
#include <pcivme_v.h>
 
#include <pcivme_io.h>
 
#include <pcivme_i.h>
 
#include <pcivme.h>
 
#include <pciif.h>
 
#include <pcivme_fifo.h>
 
//------------------------------------------------------------------------
 
// DEFINES
 
//
 
#define arraysize(p) (sizeof(p)/sizeof((p)[0]))
 
 
 
#ifndef DWORD
 
#define DWORD ULONG
 
#endif
 
 
 
#ifndef WORD
 
#define WORD USHORT
 
#endif
 
 
 
#define CTL_INDEX(x) ((x >> 2) & 0x7FF)  // get user control code as index
 
#define IRQ_LIST_LENGTH 128     // max count of irqs in FIFO for each file_obj
 
 
 
#define RESOURCE_ENTRY_COUNT 6          // WIN2000 forces to claim all entries
 
 
 
#define DOS_DEVICE_NAME L"\\DosDevices\\PCIVME:"
 
 
 
//------------------------------------------------------------------------
 
// GLOBALS
 
//
 
 
 
//------------------------------------------------------------------------
 
// FUNCTIONS
 
//
 
 
 
//------------------------------------------------------------------------
 
// exchange the pointer to Bus Error 
 
//
 
PBOOLEAN ExchangePointer(PBOOLEAN *current, PBOOLEAN next)
 
{
 
        PBOOLEAN pb;
 
 
 
        pb       = *current;
 
        *current = next;
 
 
 
        return pb;
 
}
 
 
 
//------------------------------------------------------------------------
 
// get the vmemm number out of the filename
 
//
 
NTSTATUS InterpreteFileName(PCHAR name, int *nVmemm)
 
{
 
        char *ptr = name;
 
    char *n   = "vmemm";
 
        int  h = -1;  // high part
 
        int  l = -1;  // low part
 
 
 
        if (*ptr == '\\') ptr++; // jump over leading ...
 
 
 
    while (*n)                           // compare the basename
 
          {
 
                  n++;
 
                  ptr++;
 
          }
 
          else
 
                  return STATUS_NO_SUCH_FILE;
 
 
 
        h = *ptr - '0';                  // get the number
 
        ptr++;
 
        l = *ptr - '0';
 
 
 
        if (*ptr == 0)                   // still over the end ??
 
        {
 
                l = h;
 
                h = 0;
 
        }
 
        else 
 
          ptr++;
 
 
 
        if ((h < 0) || (l < 0) || (*ptr != 0))  // anything wrong ??
 
                  return STATUS_NO_SUCH_FILE;
 
 
 
        *nVmemm = (h * 10) + l;  // calculate number
 
 
 
        if (*nVmemm >= PCIVME_MAX_VMEMM) // out of range ??
 
                  return STATUS_NO_SUCH_FILE;
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// the ultimate driver unload
 
VOID PCIVMEUnload(PDRIVER_OBJECT driverObj)
 
{
 
        int              i; 
 
        UNICODE_STRING symbol_name;
 
        if (!driverObj->DeviceObject) {
 
                KdPrint(("PCIVMEUnload() DeviceObject does not exist \n"));
 
                return;
 
        }
 
        DEVICE_EXT *ext = (DEVICE_EXT*)(driverObj->DeviceObject->DeviceExtension);
 
        int         nPCIADAs = ext->nPCIADAs;
 
        PCIADA      *pciada;
 
 
 
        KdPrint(("PCIVMEUnload() InitState %d \n", ext->nInitState ));
 
 
 
 
 
        if (ext->nInitState!=100) return;
 
 
 
        switch (ext->nInitState)
 
        {
 
                case 8:
 
                case 7:
 
                        // stop interrupts and shut off
 
                        PCIVMEDeInitPCIADAs(driverObj->DeviceObject);
 
                        PCIVMEDisConnectInterrupt(driverObj->DeviceObject);
 
 
 
                        // remove interrupt lists
 
                        for (i = 0; i < nPCIADAs; i++)
 
                        {
 
                                pciada = &ext->pciada[i];
 
 
 
                                // removeQueueFromList(...)
 
                                while (IsListEmpty(&pciada->IrqListList) == FALSE) 
 
                                {
 
                                        PLIST_ENTRY pList;
 
                                        FIFO_LIST   *next; 
 
                                
 
                                        KdPrint(("RemoveHeadList(0x%08x)\n", &pciada->IrqListList));
 
                                        pList = RemoveHeadList(&pciada->IrqListList);
 
                                        next  = CONTAINING_RECORD(pList, FIFO_LIST, entry);
 
 
 
                                        ExFreePool((PVOID)next);
 
                                }
 
                        }
 
                case 6: 
 
                        // InitializeIRPQueue has no counterpart
 
                case 5:
 
                        // KeInitializeDpc has no counterpart
 
                case 4:
 
                        // release io spaces
 
                        for (i = 0; i < nPCIADAs; i++)
 
                        {
 
                                pciada = &ext->pciada[i];
 
 
 
                                if (pciada->pvVirtLcr != NULL) 
 
                                        MmUnmapIoSpace(pciada->pvVirtLcr, LCR_SPACE);
 
                                if (pciada->pvVirtIfr != NULL) 
 
                                        MmUnmapIoSpace(pciada->pvVirtIfr, IFR_SPACE);
 
                        }
 
                case 3:
 
                        // HalGetInterruptVector has no counterpart
 
                case 2:
 
                        // HalTranslateBusAddress has no counterpart
 
                case 1:
 
                        // PCIVMEFreeResources(driverObj->DeviceObject); // not used in pnp
 
                default:
 
                case 0:
 
                        RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
 
 
 
                        // delete the symbolicLink in the registry 
 
                        IoDeleteSymbolicLink( &symbol_name);
 
 
 
                        // delete the deviceObject 
 
 
 
                        if (ext->LowerDeviceObject) IoDetachDevice(ext->LowerDeviceObject);
 
                        IoDeleteDevice(driverObj->DeviceObject);
 
        }
 
        
 
        KdPrint(("PCIVMEUnload() OK.\n"));
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// called at CreateFile()
 
NTSTATUS PCIVMEOpen(PDEVICE_OBJECT deviceObj, PIRP Irp)
 
{
 
        NTSTATUS result = STATUS_SUCCESS;
 
    ANSI_STRING name;
 
    int nVmemm;
 
        int i;
 
        DEVICE_EXT      *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
 
        PCIADA      *pciada;
 
        FILE_OBJ        *file_obj = (FILE_OBJ *)NULL;
 
 
 
        name.Buffer = NULL;
 
    name.MaximumLength = 80;
 
 
 
        result = RtlUnicodeStringToAnsiString(&name, &(Irp->Tail.Overlay.OriginalFileObject->FileName), TRUE);
 
        if (result != STATUS_SUCCESS) goto fin;
 
 
 
        result = InterpreteFileName(name.Buffer, &nVmemm);
 
    if (result != STATUS_SUCCESS) goto fin;
 
 
 
    KdPrint(("PCIVMEOpen(%d)\n", nVmemm));
 
        RtlFreeAnsiString(&name);
 
 
 
    file_obj = (FILE_OBJ *)ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_OBJ),'nepo');
 
        if (file_obj == (FILE_OBJ *)NULL)
 
        {
 
                result = STATUS_NO_MEMORY;
 
                goto fin;
 
        }
 
 
 
        file_obj->uwAssociatedVMEMM = (USHORT) nVmemm;
 
        file_obj->bAddressModifier  = 0x39;
 
        file_obj->bAccessType       = BYTE_ACCESS; 
 
        file_obj->bIncrement        = BYTE_ACCESS; // increments each byte
 
        file_obj->dwAccessBase      = 0;           // normal setting for all but extended
 
 
 
        file_obj->bQueueIrq                     = FALSE;
 
        result = InitializeFIFO(IRQ_LIST_LENGTH, &file_obj->pIrqListHandle);
 
        if (result != STATUS_SUCCESS) goto fin;
 
 
 
    Irp->Tail.Overlay.OriginalFileObject->FsContext = (PVOID)file_obj;
 
 
 
        result = PCIVMEScanVMEMM(deviceObj);
 
        if (result != STATUS_SUCCESS) goto fin;
 
 
 
        for (i = 0; i < pDevExt->nPCIADAs; i++)
 
        {
 
          pciada = &pDevExt->pciada[i];
 
 
 
          if (pciada->wModuleNumber == nVmemm) 
 
          {
 
                  pDevExt->vmemm[nVmemm] = pciada; // create association
 
                  pciada->dwLinkCount++;
 
                  break;
 
          }
 
        }
 
 
 
        if (i >= pDevExt->nPCIADAs)
 
        {
 
                result = STATUS_NO_SUCH_FILE;
 
                goto fin;
 
        }
 
 
 
        fin:
 
        Irp->IoStatus.Status = result;
 
        Irp->IoStatus.Information = 0;
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
 
 
        // be careful when releasing allocated memory !
 
        if (result != STATUS_SUCCESS) 
 
                if (file_obj != (FILE_OBJ *)NULL)
 
                        if (file_obj->pIrqListHandle != (PVOID)NULL)
 
                                DestroyFIFO(file_obj->pIrqListHandle);
 
 
 
        return result;
 
}
 
 
 
//------------------------------------------------------------------------
 
// called at close()
 
NTSTATUS PCIVMEClose(PDEVICE_OBJECT deviceObj, PIRP Irp)
 
{
 
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(deviceObj->DeviceExtension);
 
        FILE_OBJ    *file_obj = (FILE_OBJ *)NULL;
 
        PCIADA      *pciada;                    
 
 
 
        file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
 
 
    KdPrint(("PCIVMEClose(%d)\n", file_obj->uwAssociatedVMEMM));
 
 
 
        if (file_obj != (FILE_OBJ *)NULL)
 
        {
 
                pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
 
                pciada->dwLinkCount--;
 
 
 
                // remove the ListEntry(s) associated with this path
 
        removeQueueFromList(file_obj, pciada);
 
 
 
            // empty and remove the interrupt queue (if there is anything stored)
 
                DestroyFIFO(file_obj->pIrqListHandle);
 
                
 
                ExFreePool(file_obj);
 
                Irp->Tail.Overlay.OriginalFileObject->FsContext = (FILE_OBJ *)NULL;
 
        }
 
 
 
        KdPrint(("PCIVMEClose OK\n"));
 
 
 
    Irp->IoStatus.Status = STATUS_SUCCESS;
 
        Irp->IoStatus.Information = 0;
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// called at 
 
NTSTATUS PCIVMEShutdown(PDEVICE_OBJECT deviceObj, PIRP  irp  )
 
{
 
        UNREFERENCED_PARAMETER(irp);
 
 
 
    KdPrint(("PCIVMEShutdown()\n"));
 
 
 
        // deinit interfaces and interrupts
 
        PCIVMEDeInitPCIADAs(deviceObj);
 
 
 
    KdPrint(("PCIVMEShutdown() OK\n"));
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// called at ioctl()
 
NTSTATUS PCIVMEDeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
 
{
 
        PIO_STACK_LOCATION IrpStack;
 
        int   nIndex;
 
 
 
        IrpStack  = IoGetCurrentIrpStackLocation(Irp);
 
        nIndex    = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
 
 
 
    KdPrint(("PCIVMEDeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
 
 
 
        if (nIndex > CTL_INDEX(PCIVME_LAST_CTL_CODE))
 
        {
 
                Irp->IoStatus.Status      = STATUS_UNSUCCESSFUL;
 
                Irp->IoStatus.Information = 0;
 
                IoCompleteRequest(Irp,IO_NO_INCREMENT);
 
 
 
        KdPrint(("PCIVMEDeviceControl() FAIL.\n"));
 
 
 
                return STATUS_UNSUCCESSFUL;
 
        }
 
 
 
        return ioctl[nIndex](deviceObj, Irp, IrpStack);
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// called at read()
 
NTSTATUS PCIVMERead(PDEVICE_OBJECT device_Obj, PIRP Irp)
 
{
 
        NTSTATUS        Status        = STATUS_SUCCESS;
 
        PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
 
        PVOID           pOutputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
 
        LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
 
        FILE_OBJ        *file_obj           = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
  PCIADA      *pciada             = pDevExt->vmemm[file_obj->uwAssociatedVMEMM]; 
 
        register ULONG Address  = IrpStack->Parameters.Read.ByteOffset.LowPart  + file_obj->dwAccessBase;   
 
        ULONG storeLength                   = 0;
 
        PBOOLEAN pbPrevBusError;
 
 
 
        KdPrint(("PCIVMERead(%d)\n", file_obj->uwAssociatedVMEMM));
 
 
 
        // do here in between what has to be done -----------------
 
  if (Address & file_obj->dwAddressMask)     // don't do unaligned transfers
 
                Status = STATUS_DATATYPE_MISALIGNMENT;
 
        else
 
        {
 
                register ULONG Length = IrpStack->Parameters.Read.Length;     
 
                register ULONG blockLength;
 
                register ULONG pageAddress;
 
                register ULONG toNextPage;
 
                KIRQL              oldIrql;
 
 
 
                Length     &= ~file_obj->dwAddressMask; // align to integer increments
 
                storeLength = Length;
 
                
 
                // lock other users out
 
                KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
 
 
 
                // check for modifier
 
                if (pciada->bModifier != file_obj->bAddressModifier)
 
                {
 
                        WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
 
                        pciada->bModifier = file_obj->bAddressModifier;
 
                }
 
                
 
                // do the read ---
 
                file_obj->bBusError = FALSE; 
 
                pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
 
                while (Length)
 
                {
 
                        pageAddress = Address & ~VME_ADR_MASK;
 
                        if (pageAddress != pciada->dwVMEPage)
 
                        {
 
                                WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
 
                                pciada->dwVMEPage = pageAddress;
 
                        }
 
 
 
                        toNextPage  = (pageAddress + VME_ADR_MASK + 1) - Address;
 
                        blockLength = (toNextPage < Length) ? toNextPage : Length;
 
 
 
                        KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
 
                                                                                Address, blockLength, Length));
 
 
 
                        file_obj->fRead(pOutputBuffer , blockLength, (PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)));
 
 
 
                        Length  -= blockLength;
 
                        Address += blockLength;
 
                        pOutputBuffer = (PVOID)((PUCHAR)pOutputBuffer + blockLength);
 
                } 
 
 
 
                // release the lock
 
                KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
 
                ExchangePointer(&pciada->pbBusError, pbPrevBusError);
 
                if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
 
 
 
            if (file_obj->bIncrement)  // only when increment to next is on
 
                        *fileOffset = 
 
                                RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
 
        }
 
        // do here in between what has to be done end -------------
 
 
 
        Irp->IoStatus.Status      = Status;  
 
        Irp->IoStatus.Information = storeLength;  
 
        IoCompleteRequest(Irp,IO_NO_INCREMENT);  
 
 
 
    KdPrint(("PCIVMERead(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// called at write()
 
NTSTATUS PCIVMEWrite(PDEVICE_OBJECT device_Obj, PIRP Irp)
 
{
 
        NTSTATUS        Status        = STATUS_SUCCESS;
 
        PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
 
        PVOID           pInputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
 
        LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
 
        FILE_OBJ        *file_obj           = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
  PCIADA      *pciada             = pDevExt->vmemm[file_obj->uwAssociatedVMEMM]; 
 
        register ULONG Address  = IrpStack->Parameters.Write.ByteOffset.LowPart + file_obj->dwAccessBase;   
 
        ULONG storeLength                   = 0;
 
        PBOOLEAN pbPrevBusError;
 
 
 
        KdPrint(("PCIVMEWrite(%d)\n", file_obj->uwAssociatedVMEMM));
 
 
 
        // do here in between what has to be done -----------------
 
  if (Address & file_obj->dwAddressMask)     // don't do unaligned transfers
 
                Status = STATUS_DATATYPE_MISALIGNMENT;
 
        else
 
        {
 
                register ULONG Length = IrpStack->Parameters.Write.Length;     
 
                register ULONG blockLength;
 
                register ULONG pageAddress;
 
                register ULONG toNextPage;
 
                KIRQL              oldIrql; 
 
 
 
                Length     &= ~file_obj->dwAddressMask; // align to integer increments
 
                storeLength = Length;
 
                                                       // check for modifier
 
                // lock other users out
 
                KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
 
 
 
                if (pciada->bModifier != file_obj->bAddressModifier)
 
                {
 
                        WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
 
                        pciada->bModifier = file_obj->bAddressModifier;
 
                }
 
                
 
                // do the read ---
 
                file_obj->bBusError = FALSE;
 
                pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
 
                while (Length)
 
                {
 
                        pageAddress = Address & ~VME_ADR_MASK;
 
                        if (pageAddress != pciada->dwVMEPage)
 
                        {
 
                                WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
 
                                pciada->dwVMEPage = pageAddress;
 
                        }
 
 
 
                        toNextPage  = (pageAddress + VME_ADR_MASK + 1) - Address;
 
                        blockLength = (toNextPage < Length) ? toNextPage : Length;
 
 
 
                        KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
 
                                                                                Address, blockLength, Length));
 
 
 
                        file_obj->fWrite((PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)) , blockLength, pInputBuffer);
 
 
 
                        Length  -= blockLength;
 
                        Address += blockLength;
 
                        pInputBuffer = (PVOID)((PUCHAR)pInputBuffer + blockLength);
 
                } 
 
 
 
                // release the lock
 
                KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
 
                ExchangePointer(&pciada->pbBusError, pbPrevBusError);
 
                if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
 
 
 
                if (file_obj->bIncrement)  // only when increment to next is on
 
                        *fileOffset =   RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
 
        }
 
        // do here in between what has to be done end -------------
 
 
 
        Irp->IoStatus.Status      = Status;  
 
        Irp->IoStatus.Information = storeLength;  
 
        IoCompleteRequest(Irp,IO_NO_INCREMENT);  
 
 
 
    KdPrint(("PCIVMEWrite(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
} 
 
 
 
#ifdef DO_CLEANUP
 
//------------------------------------------------------------------------
 
// called at cancel of a path
 
NTSTATUS PCIVMECancel(PDEVICE_OBJECT device_Obj, PIRP Irp)
 
{
 
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        PIRP     pIrpCancel;
 
 
 
        KdPrint(("PCIVMECancel()\n"));
 
 
 
        // remove all queued IRPs of this file_obj
 
        do
 
        {
 
                pIrpCancel = RemoveIRPfromQueue(device_Obj, file_obj);
 
 
 
                if (pIrpCancel == (PIRP)NULL)
 
                {
 
                        IoReleaseCancelSpinLock(pIrpCancel->CancelIrql); 
 
                        break;
 
                }
 
                else
 
                {
 
                        IoAcquireCancelSpinLock(pIrpCancel->CancelIrql);
 
 
 
                        // mark irp as not pending
 
                        IoSetCancelRoutine(pIrpCancel, NULL); 
 
 
 
                        IoReleaseCancelSpinLock(pIrpCancel->CancelIrql); 
 
 
 
                        pIrpCancel->IoStatus.Status = STATUS_CANCELLED; 
 
                        pIrpCancel->IoStatus.Information = 0; 
 
                }
 
        } while (pIrpCancel != (PIRP)NULL);
 
 
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
 
 
 
        KdPrint(("PCIVMECancel(OK)\n"));
 
 
 
        return STATUS_SUCCESS;
 
}
 
#endif
 
 
 
 
 
// http://read.pudn.com/downloads148/sourcecode/windows/vxd/640413/agp/agplib/init.c__.htm
 
NTSTATUS   
 
QueryBusInterface(   
 
    IN PDEVICE_OBJECT DeviceObject,   
 
    OUT PBUS_INTERFACE_STANDARD BusInterface   
 
    )   
 
/*++  
 
  
 
Routine Description:  
 
  
 
    Sends a query-interface IRP to the specified device object  
 
    to obtain the BUS_INTERFACE_STANDARD interface.  
 
  
 
Arguments:  
 
  
 
    DeviceObject - Supplies the device object to send the BUS_INTERFACE_STANDARD to  
 
  
 
    BusInterface - Returns the bus interface  
 
  
 
Return Value:  
 
  
 
    STATUS_SUCCESS if successful  
 
    NTSTATUS if unsuccessful  
 
  
 
--*/   
 
   
 
{   
 
    PIRP Irp;   
 
    KEVENT Event;   
 
    PIO_STACK_LOCATION IrpSp;   
 
    IO_STATUS_BLOCK IoStatusBlock;   
 
    NTSTATUS Status;   
 
//    ULONG ReturnLength;   
 
   
 
    KeInitializeEvent( &Event, NotificationEvent, FALSE );   
 
    Irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,   
 
                                        DeviceObject,   
 
                                        NULL,   
 
                                        0,   
 
                                        NULL,   
 
                                        &Event,   
 
                                        &IoStatusBlock );   
 
    if (Irp == NULL) {   
 
        return(STATUS_INSUFFICIENT_RESOURCES);   
 
    }   
 
   
 
    IrpSp = IoGetNextIrpStackLocation( Irp );   
 
    ASSERT(IrpSp != NULL);   
 
    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;   
 
    IrpSp->MajorFunction = IRP_MJ_PNP;   
 
    IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;   
 
    IrpSp->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;   
 
    IrpSp->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);   
 
    IrpSp->Parameters.QueryInterface.Version = 1;   
 
    IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE) BusInterface;   
 
    IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;   
 
   
 
    Status = IoCallDriver(DeviceObject, Irp);   
 
    if (Status == STATUS_PENDING) {   
 
        KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );   
 
        Status = Irp->IoStatus.Status;   
 
    }   
 
   
 
    return(Status);   
 
}   
 
   
 
//------------------------------------------------------------------------
 
// search for pciada's
 
//
 
 
 
NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
 
{
 
  PCI_SLOT_NUMBER   SlotNumber;
 
  PCI_COMMON_CONFIG pci_config; 
 
  PBUS_INTERFACE_STANDARD busInterface;
 
  PCIADA            *pciada;
 
 
 
  ULONG   propertyAddress, length;
 
  USHORT  FunctionNumber, DeviceNumber;
 
  int               *found;
 
  int               i;
 
  NTSTATUS          status;
 
  int  BytesRead;
 
  KdPrint(("SearchDevices()\n"));
 
 
 
  // prepare structures ----------------------------------------
 
  found = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
 
  *found = 0;
 
  for (i = 0; i < PCIVME_MAX_PCIADA; i++)
 
  {
 
        pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i]; 
 
 
 
        pciada->Bus                = -1;
 
    pciada->Slot.u.AsULONG     = 0xFFFFFFFF;
 
  }
 
 
 
  // search for pciada's ---------------------------------------
 
  SlotNumber.u.bits.Reserved = 0;
 
  busInterface = (PBUS_INTERFACE_STANDARD)ExAllocatePool(NonPagedPool,
 
          sizeof(BUS_INTERFACE_STANDARD));
 
  if (busInterface == NULL)
 
  {
 
          return STATUS_INSUFFICIENT_RESOURCES;
 
  }
 
  ((DEVICE_EXT*)(device_Obj->DeviceExtension))->busInterface = busInterface;
 
  status = QueryBusInterface(device_Obj, busInterface);
 
  BytesRead = busInterface->GetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, &pci_config, 0, PCI_COMMON_HDR_LENGTH);
 
 
 
  pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[0];
 
 
 
                //http://www.hollistech.com/Resources/Misc%20articles/getbusdata.htm
 
                //IoGetDeviceProperty
 
                //There are other differnt methods to send a request to lower layer. One method is 
 
        //by sending IRP_MN_READ_CONFIG to lower driver. You will recieve 
 
        //PCI_COMMON_CONFIG structure.
 
                // http://msdn.microsoft.com/en-us/library/windows/hardware/ff536890(v=vs.85).aspx
 
                // http://www.rdos.net/svn/tags/V9.2.5/watcom/bld/src/win32/miniwdm/dev/wdmdev.c
 
 
 
                if ((pci_config.VendorID    == PCIVME_VENDOR_ID) &&
 
                        (pci_config.DeviceID    == PCIVME_DEVICE_ID) &&
 
                        (pci_config.u.type0.SubSystemID == PCIVME_SUBSYS_ID) &&
 
                        (pci_config.u.type0.SubVendorID == PCIVME_SUBVEN_ID) &&
 
                        (pci_config.u.type0.BaseAddresses[2]))
 
                {
 
               pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found]; 
 
 
 
               memcpy(&pciada
->PCIDevice
, &pci_config
, sizeof(pci_config
));  
        
 
                   IoGetDeviceProperty(device_Obj,
 
                           DevicePropertyBusNumber,
 
                           sizeof(ULONG),
 
                           (PVOID)&(pciada->Bus),
 
                           &length);
 
 
 
                   IoGetDeviceProperty(device_Obj,
 
                           DevicePropertyAddress,
 
                           sizeof(ULONG),
 
                           (PVOID)&propertyAddress,
 
                           &length);
 
                   // 
 
                   // For PCI, the DevicePropertyAddress has device number 
 
                   // in the high word and the function number in the low word. 
 
                   // 
 
                   FunctionNumber = (USHORT)((propertyAddress)& 0x0000FFFF);
 
                   DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
 
                   pciada->Slot.u.AsULONG = DeviceNumber;
 
                   KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
 
 
 
                   (*found)++;
 
                   if (*found >= PCIVME_MAX_PCIADA) return STATUS_SUCCESS;
 
                        
 
        }
 
  KdPrint(("SearchDevices() found %d devices\n", (*found)));
 
  return STATUS_SUCCESS;
 
}
 
 
 
//---------------------------------------------------------------
 
// function to call for bug fix of PLX9050 build in bug
 
//
 
NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
 
{
 
        // http://permalink.gmane.org/gmane.linux.kernel.pci/18419
 
        DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
 
        int i;
 
        ULONG dwData;
 
        PCIADA *pciada;
 
        PBUS_INTERFACE_STANDARD busInterface;
 
 
 
        KdPrint(("PLX9050BugFix()\n"));
 
        busInterface = DeviceExtension->busInterface;
 
        for (i = 0; i < DeviceExtension->nPCIADAs; i++)
 
        {
 
                pciada = &DeviceExtension->pciada[i]; 
 
 
 
                if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[0]) & 0x80)
 
                {      
 
                        KdPrint(("Changing address 0:0x%p with 4:0x%p\n", 
 
                                pciada->PCIDevice.u.type0.BaseAddresses[0],
 
                                pciada->PCIDevice.u.type0.BaseAddresses[4]));
 
 
 
                        pciada->PCIDevice.u.type0.BaseAddresses[0] =           // exchange
 
                                pciada->PCIDevice.u.type0.BaseAddresses[4];
 
                        pciada->PCIDevice.u.type0.BaseAddresses[4] = dwData;
 
 
 
                        if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0], 0x10, 4) != 4)
 
                                return STATUS_UNSUCCESSFUL;
 
                        
 
                        if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[4], 0x20, 4) != 4)
 
                                return STATUS_UNSUCCESSFUL;
 
                        
 
                }
 
      
 
                if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[1]) & 0x80)
 
                {
 
                        KdPrint(("Changing address 1:0x%p with 5:0x%p\n", 
 
                                pciada->PCIDevice.u.type0.BaseAddresses[1],
 
                                pciada->PCIDevice.u.type0.BaseAddresses[5]));
 
 
 
                  pciada->PCIDevice.u.type0.BaseAddresses[1] =           // exchange
 
                                pciada->PCIDevice.u.type0.BaseAddresses[5];
 
                  pciada->PCIDevice.u.type0.BaseAddresses[5] = dwData;
 
 
 
                  if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1], 0x14, 4) != 4)
 
                          return STATUS_UNSUCCESSFUL;
 
                 
 
                  if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5], 0x24, 4) != 4)
 
                          return STATUS_UNSUCCESSFUL;
 
                 
 
                }
 
        }
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
static VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list)
 
{                                                       // ShowResources
 
        PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = list->PartialDescriptors;
 
        ULONG nres = list->Count;
 
        ULONG i;
 
 
 
        for (i = 0; i < nres; ++i, ++resource)
 
        {                                               // for each resource
 
                ULONG type = resource->Type;
 
 
 
                static char* namelow[] = {
 
                        "CmResourceTypeNull",//                0   // ResType_All or ResType_None (0x0000)
 
                        "CmResourceTypePort",//               1   // ResType_IO (0x0002)
 
                        "CmResourceTypeInterrupt",//          2   // ResType_IRQ (0x0004)
 
                        "CmResourceTypeMemory",//             3   // ResType_Mem (0x0001)
 
                        "CmResourceTypeDma",//                4   // ResType_DMA (0x0003)
 
                        "CmResourceTypeDeviceSpecific",//      5   // ResType_ClassSpecific (0xFFFF)
 
                        "CmResourceTypeBusNumber",//          6   // ResType_BusNumber (0x0006)
 
                        "CmResourceTypeMemoryLarge" //        7   // ResType_MemLarge (0x0007)
 
                };
 
                static char* namehigh[] = {
 
                        //"CmResourceTypeNonArbitrated" ,//    128   // Not arbitrated if 0x80 bit set
 
                        "CmResourceTypeConfigData",//       128   // ResType_Reserved (0x8000)
 
                        "CmResourceTypeDevicePrivate",//    129   // ResType_DevicePrivate (0x8001)
 
                        "CmResourceTypePcCardConfig",//     130   // ResType_PcCardConfig (0x8002)
 
                        "CmResourceTypeMfCardConfig",//     131   // ResType_MfCardConfig (0x8003)
 
                        "CmResourceTypeConnection" //       132   // ResType_Connection (0x8004)
 
                };
 
 
 
                if (type<8) KdPrint((" [%d] type %s", type, type < arraysize(namelow) ? namelow[type] : "unknown"));
 
                if (type>127) KdPrint((" [%d] type %s", type, type-128 < arraysize(namehigh) ? namehigh[type-128] : "unknown"));
 
                switch (type)
 
                {                                       // select on resource type
 
                case CmResourceTypePort:
 
                                KdPrint((" start ADDR=0x%p  0x%8X%8.8lX length %X\n",
 
                                resource->u.Port.Start, resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
 
                                resource->u.Port.Length));
 
                        break;
 
                case CmResourceTypeMemory:
 
                        KdPrint((" %d start ADDR=0x%p \n", i,  resource->u.Memory.Start ));
 
                        break;
 
 
 
                case CmResourceTypeInterrupt:
 
                        KdPrint(("  IRQL %d, vector %d, affinity %d\n",
 
                                resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
 
                                resource->u.Interrupt.Affinity));
 
                        break;
 
 
 
                case CmResourceTypeDma:
 
                        KdPrint(("  channel %d, port %X\n",
 
                                resource->u.Dma.Channel, resource->u.Dma.Port));
 
 
 
                        
 
                        
 
                }                                       // select on resource type
 
        }                                               // for each resource
 
}                                                       // ShowResources
 
 
 
 
 
//------------------------------------------------------------------------
 
//  reserve resources for PCIADAs 
 
//
 
NTSTATUS PCIVMEExtractResources(PCIADA *pciada, PIRP irp) 
 
{
 
        //PCM_RESOURCE_LIST pResourceList;
 
        ///PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
 
        PCM_PARTIAL_RESOURCE_LIST pPartialList = NULL;
 
        PCM_PARTIAL_RESOURCE_LIST pListTranslated = NULL;
 
        PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
 
        int i;
 
        int bug = 0;
 
 
 
        KdPrint(("PCIVMEExtractResources()\n"));
 
 
 
        ///pResourceList   = pList;
 
        ///pFullDescriptor = pResourceList->List;
 
        ///pPartialList    = &pFullDescriptor->PartialResourceList;
 
        PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
 
        if (stack->Parameters.StartDevice.AllocatedResources)
 
        pPartialList = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
 
        KdPrint(("Allocated Resources:------------------\n"));
 
        ShowResources(pPartialList);
 
        
 
        int plcount = 0;
 
        for (i=0; i<(int)pPartialList->Count; i++) 
 
        {
 
                pPartialDescriptor = &pPartialList->PartialDescriptors[i];
 
                
 
                switch (pPartialDescriptor->Type) 
 
                {
 
                        case CmResourceTypeInterrupt:
 
                                pciada->Irql     = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
 
                                pciada->Vector   = pPartialDescriptor->u.Interrupt.Vector;
 
                                pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
 
 
 
                                KdPrint(("AllocatedResources Irq    : Irql: %d, Vector: %d, Affinity: %d\n", 
 
                                        pciada->Irql, pciada->Vector, pciada->Affinity));
 
                                break;
 
                        case CmResourceTypeDma:
 
                                KdPrint(("AllocatedResources Dma    : \n")); 
 
                                break;
 
                        case CmResourceTypePort:
 
 
 
                                KdPrint(("AllocatedResources Port   : 0x%p\n", pPartialDescriptor->u.Port.Start)); 
 
                                break;
 
                        case CmResourceTypeMemory:
 
                                // special handling of PLXBUG here because of WIN2000
 
                                // WIN2000 doesn't recognize late address changes
 
                                if (!bug)
 
                                {
 
                                        if (plcount == 0)
 
                                        {
 
                                                pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
 
 
 
                                                if (pciada->pvPhysLcr.LowPart & 0x80) {
 
                                                        bug = 1;
 
                                                        KdPrint(("AllocatedResources PLXBug\n"));
 
                                                }
 
                                        }
 
                                }
 
                                else
 
                                {
 
                                        if (plcount == 3)
 
                                                pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
 
                                }
 
 
 
                                if (plcount == 2){
 
                                        pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
 
                                        KdPrint(("PCIVMEExtractResources() IFR=0x%p \n", pciada->pvPhysIfr));
 
                                }
 
                                KdPrint(("[%d] AllocatedResources Memory : 0x%p\n", plcount, (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart)); 
 
                                break;
 
                }
 
                if (pPartialDescriptor->Type < 8) plcount++;
 
        }
 
 
 
        KdPrint(("PCIVMEExtractResources() LCR=0x%p IFR=0x%p \n", pciada->pvPhysLcr, pciada->pvPhysIfr));
 
 
 
        if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
 
                pListTranslated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
 
        KdPrint(("Translated Resources:------------------\n"));
 
        ShowResources(pListTranslated);
 
        plcount = 0;
 
        bug     = 0;
 
        for (i = 0; i<(int)pPartialList->Count; i++)
 
        {
 
                pPartialDescriptor = &pListTranslated->PartialDescriptors[i];
 
 
 
                switch (pPartialDescriptor->Type)
 
                {
 
                case CmResourceTypeInterrupt:
 
                        pciada->Irql = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
 
                        pciada->Vector = pPartialDescriptor->u.Interrupt.Vector;
 
                        pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
 
 
 
                        KdPrint(("AllocatedResourcesTranslated Irq    : Irql: %d, Vector: %d, Affinity: %d\n",
 
                                pciada->Irql, pciada->Vector, pciada->Affinity));
 
                        break;
 
                case CmResourceTypeDma:
 
                        KdPrint(("AllocatedResourcesTranslated Dma    : \n"));
 
                        break;
 
                case CmResourceTypePort:
 
 
 
                        KdPrint(("AllocatedResourcesTranslated Port   : 0x%p\n", pPartialDescriptor->u.Port.Start));
 
                        break;
 
                case CmResourceTypeMemory:
 
                        // special handling of PLXBUG here because of WIN2000
 
                        // WIN2000 doesn't recognize late address changes
 
                        if (!bug)
 
                        {
 
                                if (plcount == 0)
 
                                {
 
                                        pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
 
                                        KdPrint(("0 PCIVMEExtractResources() LCR=0x%p \n", pciada->pvPhysLcr));
 
                                        if (pciada->pvPhysLcr.LowPart & 0x80) {
 
                                                bug = 1;
 
                                                KdPrint(("AllocatedResourcesTranslated PLXBug\n"));
 
                                        }
 
                                }
 
                        }
 
                        else
 
                        {
 
                                if (plcount == 3){
 
                                        pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
 
                                        KdPrint(("3 PCIVMEExtractResources() LCR=0x%p \n", pciada->pvPhysLcr));
 
                                }
 
                        }
 
 
 
                        if (plcount == 2){
 
                                pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
 
                                KdPrint(("2 PCIVMEExtractResources() IFR=0x%p \n", pciada->pvPhysIfr));
 
                        }
 
 
 
                        KdPrint(("[%d] AllocatedResourcesTranslated Memory : 0x%p\n", plcount, (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
 
                        break;
 
                }
 
                if (pPartialDescriptor->Type < 8) plcount++;
 
        }
 
 
 
 
 
 
 
        if (pciada->Irql == 0)
 
                return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
 
 
 
        KdPrint(("PCIVMEExtractResources() Translated LCR=0x%p IFR=0x%p \n", pciada->pvPhysLcr, pciada->pvPhysIfr));
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
NTSTATUS PCIVMEReserveResources(PDEVICE_OBJECT device_Obj, PIRP irp)
 
{
 
        //PCM_RESOURCE_LIST pList = NULL;
 
        NTSTATUS result = STATUS_SUCCESS;
 
        int i;
 
        DEVICE_EXT *pDevExt = (DEVICE_EXT*)(device_Obj->DeviceExtension);
 
        int nPCIADAs = pDevExt->nPCIADAs;
 
        PCIADA *pciada;
 
    UNICODE_STRING DriverClassName;
 
    
 
        KdPrint(("PCIVMEReserveResources()\n"));
 
 
 
        // prepare resource claiming
 
        //RtlInitUnicodeString(&DriverClassName, L"PCICC32");
 
        RtlInitUnicodeString(&DriverClassName, L"PCIVME");
 
        // cycle through all busses and slots assigned to PCIADAs
 
        for (i = 0; i < nPCIADAs; i++)
 
    {
 
                pciada = &pDevExt->pciada[i];
 
 
 
                //result = HalAssignSlotResources(NULL, &DriverClassName, device_Obj->DriverObject, device_Obj, 
 
                //      PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, &pList);
 
                /*
 
                result = IoReportDetectedDevice(device_Obj->DriverObject, PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, pList, NULL, FALSE, &device_Obj);
 
                if (result != STATUS_SUCCESS){
 
                        KdPrint(("PCIVMEReserveResources(0x%08x) HalAssignSlotResources  ***ERROR*** faliure to get slot information\n", result));
 
                        break;
 
                }
 
                */
 
                result = PCIVMEExtractResources(pciada, irp);
 
 
 
                if (result != STATUS_SUCCESS){
 
                        KdPrint(("PCIVMEReserveResources(0x%08x) PCIVMEExtractResources\n", result));
 
                        break;
 
                }
 
        }
 
 
 
        // its my part to free allocated resources
 
        //if (pList != NULL) ExFreePoolWithTag(pList,'nepo');
 
 
 
        KdPrint(("PCIVMEReserveResources(0x%08x)\n", result));
 
 
 
        return result;
 
};
 
 
 
 
 
//------------------------------------------------------------------------
 
//  translate memory resources to neutral for PCIADAs 
 
//
 
NTSTATUS PCIVMETranslateBusAddresses(PDEVICE_OBJECT device_Obj,  PIRP irp)
 
{
 
        int              i;
 
        NTSTATUS         result = STATUS_SUCCESS;
 
        int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
 
        ULONG            memType0, memType2;
 
        PCIADA           *pciada;
 
        PCM_PARTIAL_RESOURCE_LIST pPartialList = NULL;
 
        PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
 
        if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
 
       pPartialList = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
 
 
 
   
 
        for (i = 0; i < nPCIADAs; i++)
 
        {
 
      pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
 
 
 
          memType0 = memType2 = 0;
 
          /*
 
          if (!(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysLcr, &memType0, 
 
                                                               &pciada->pvPhysLcr)) ||
 
              !(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysIfr, &memType2, 
 
                                                               &pciada->pvPhysIfr)))
 
          {
 
                  result = STATUS_UNSUCCESSFUL;
 
                  break;
 
          }
 
          */
 
          KdPrint(("PCIADA %d TranslateBusAddresseses() -- no translation is made\n", i));
 
 
 
          if ((memType0) || (memType2))
 
          {
 
                  result = STATUS_UNSUCCESSFUL;
 
                  break;
 
          }
 
        }
 
   
 
        return result;
 
}
 
 
 
//------------------------------------------------------------------------
 
//  map address spaces to virtual addresses
 
//
 
NTSTATUS PCIVMEMapIOspace(PDEVICE_OBJECT device_Obj)
 
{
 
        int              i;
 
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
 
        int                              nPCIADAs = pDevExt->nPCIADAs;
 
        PCIADA           *pciada;
 
 
 
        KdPrint(("PCIVMEMapIOspace()\n"));
 
 
 
        for (i = 0; i < nPCIADAs; i++)
 
        {
 
       pciada = &pDevExt->pciada[i];
 
 
 
       if ((pciada->pvVirtLcr = MmMapIoSpace(pciada->pvPhysLcr, LCR_SPACE, FALSE)) == NULL) 
 
          return STATUS_UNSUCCESSFUL;
 
       if ((pciada->pvVirtIfr = MmMapIoSpace(pciada->pvPhysIfr, IFR_SPACE, FALSE)) == NULL) 
 
          return STATUS_UNSUCCESSFUL;
 
 
 
           KdPrint(("PCIADA %d: LCR 0x%08x IFR 0x%08x\n", 
 
                                         i, pciada->pvVirtLcr, pciada->pvVirtIfr));
 
 
 
           pciada->pwIntCSR = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x4C);
 
           pciada->pwCntrl  = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x50);
 
        }
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
//  initializes and registers a DPC routine for each pciada
 
//
 
NTSTATUS InitializeCustomDPCObjects(PDEVICE_OBJECT device_object)
 
{
 
        int              i;
 
        int nPCIADAs = ((DEVICE_EXT*)(device_object->DeviceExtension))->nPCIADAs;
 
        PCIADA           *pciada;
 
 
 
        KdPrint(("InitializeCustomDPCObject()\n"));
 
 
 
        for (i = 0; i < nPCIADAs; i++)
 
        {
 
                pciada = &((DEVICE_EXT*)(device_object->DeviceExtension))->pciada[i];
 
                KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
 
        }
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
//  initializes the queue for storing IRPs waiting for vectors
 
// 
 
NTSTATUS InitializeIRPQueue(PDEVICE_OBJECT device_Obj)
 
{
 
        DEVICE_EXT *pDevExt = ((DEVICE_EXT*)(device_Obj->DeviceExtension));
 
 
 
        KdPrint(("InitializeIRPQueue()\n"));
 
 
 
        KeInitializeSpinLock(&pDevExt->IRPLock);
 
        InitializeListHead(&pDevExt->IRPList);
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// init structures a.s.o.
 
//
 
VOID PCIVMESoftInit(PDEVICE_OBJECT device_Obj)
 
{
 
        int i;
 
        PCIADA *pciada;
 
 
 
        for (i = 0; i < PCIVME_MAX_PCIADA; i++)
 
        {
 
                pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
 
 
 
                pciada->pvPhysLcr.QuadPart = pciada->pvPhysIfr.QuadPart = 0;
 
                pciada->pvVirtLcr = pciada->pvVirtIfr = NULL;
 
 
 
                pciada->bConnected     = FALSE;   // connection still not verified
 
                pciada->bWordMode      = TRUE;
 
                pciada->bSysControl    = FALSE;
 
                pciada->wModuleNumber  = 0xFFFF;
 
                pciada->wFPGAVersion   = 0xFFFF;
 
                pciada->wModuleType    = 1;       // always VMEMM
 
 
 
                pciada->InterruptObject = NULL;
 
                pciada->Irql                    = 0;
 
                pciada->Vector          = 0;
 
                pciada->Affinity                = 0;
 
 
 
                pciada->dwLinkCount     = 0;
 
                                        
 
                KeInitializeSpinLock(&pciada->IrqListLock);
 
                KeInitializeSpinLock(&pciada->AccessLock);
 
 
 
                InitializeListHead(&pciada->IrqListList);  // start of list of irq fifos
 
 
 
                pciada->nInterruptHandlers = 0;
 
        }
 
 
 
        // no vmemm associated to any PCIADA
 
        for (i = 0; i < PCIVME_MAX_VMEMM; i++)
 
          ((DEVICE_EXT*)(device_Obj->DeviceExtension))->vmemm[i] = NULL;
 
}
 
 
 
NTSTATUS OnRequestComplete(PDEVICE_OBJECT fdo, PIRP Irp, PKEVENT pev)
 
{
 
        UNREFERENCED_PARAMETER(fdo);
 
        UNREFERENCED_PARAMETER(Irp);
 
        KeSetEvent(pev, 0, FALSE);
 
        return STATUS_MORE_PROCESSING_REQUIRED;
 
}
 
 
 
NTSTATUS CompleteRequest(PIRP Irp, NTSTATUS status, ULONG_PTR Information)
 
{
 
        Irp->IoStatus.Status = status;
 
        Irp->IoStatus.Information = Information;
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
        return status;
 
}
 
NTSTATUS ForwardAndWait(PDEVICE_OBJECT fdo, PIRP Irp)
 
{
 
        KEVENT event;
 
        KeInitializeEvent(&event, NotificationEvent, FALSE);
 
        IoCopyCurrentIrpStackLocationToNext(Irp);
 
        IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete, (PVOID)&event, TRUE, TRUE, TRUE);
 
        PDEVICE_EXT pdx = (PDEVICE_EXT ) fdo->DeviceExtension;
 
        IoCallDriver(pdx->LowerDeviceObject, Irp);
 
        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
 
        return Irp->IoStatus.Status;
 
}
 
 
 
NTSTATUS HandleStartDevice(PDEVICE_OBJECT fdo, PIRP Irp)
 
{
 
        PIO_STACK_LOCATION stack;
 
        Irp->IoStatus.Status = STATUS_SUCCESS;
 
        NTSTATUS status = ForwardAndWait(fdo, Irp);
 
        if (!NT_SUCCESS(status))
 
                return CompleteRequest(Irp, status, Irp->IoStatus.Information);
 
        
 
        stack = IoGetCurrentIrpStackLocation(Irp);
 
        status = PCIVMEStartDevice(fdo, Irp);
 
        return CompleteRequest(Irp, status, Irp->IoStatus.Information);
 
}
 
 
 
 
 
NTSTATUS DefaultPnpHandler(PDEVICE_OBJECT fdo, PIRP Irp)
 
{
 
        IoSkipCurrentIrpStackLocation(Irp);
 
        PDEVICE_EXT pdx = (PDEVICE_EXT )fdo->DeviceExtension;
 
        return IoCallDriver(pdx->LowerDeviceObject, Irp);
 
}
 
 
 
NTSTATUS HandleStopDevice(PDEVICE_OBJECT fdo, PIRP Irp)
 
{
 
        IoSkipCurrentIrpStackLocation(Irp);
 
        UNICODE_STRING symbol_name;
 
        RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
 
    // delete the symbolicLink in the registry 
 
        IoDeleteSymbolicLink(&symbol_name);
 
        DEVICE_EXT *ext = (DEVICE_EXT*)(fdo->DeviceExtension);
 
        // delete the busInterface and deviceObject 
 
        if (ext->busInterface) {
 
                (*ext->busInterface->InterfaceDereference)(ext->busInterface->Context);
 
                ext->busInterface = NULL;
 
        }
 
        if (ext->LowerDeviceObject) IoDetachDevice(ext->LowerDeviceObject);
 
        IoDeleteDevice(fdo);
 
        KdPrint(("HandleStopDevice (OK)\n"));
 
        return STATUS_SUCCESS;
 
}
 
 
 
 
 
NTSTATUS PCIVMEDispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)
 
{
 
        PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
 
        ULONG fcn = stack->MinorFunction;
 
        static char* pnpname[] = {
 
                "IRP_MN_START_DEVICE",
 
                "IRP_MN_QUERY_REMOVE_DEVICE",
 
                "IRP_MN_REMOVE_DEVICE",
 
                "IRP_MN_CANCEL_REMOVE_DEVICE",
 
                "IRP_MN_STOP_DEVICE",
 
                "IRP_MN_QUERY_STOP_DEVICE",
 
                "IRP_MN_CANCEL_STOP_DEVICE",
 
                "IRP_MN_QUERY_DEVICE_RELATIONS",
 
                "IRP_MN_QUERY_INTERFACE",
 
                "IRP_MN_QUERY_CAPABILITIES",
 
                "IRP_MN_QUERY_RESOURCES",
 
                "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
 
                "IRP_MN_QUERY_DEVICE_TEXT",
 
                "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
 
                "",
 
                "IRP_MN_READ_CONFIG",
 
                "IRP_MN_WRITE_CONFIG",
 
                "IRP_MN_EJECT",
 
                "IRP_MN_SET_LOCK",
 
                "IRP_MN_QUERY_ID",
 
                "IRP_MN_QUERY_PNP_DEVICE_STATE",
 
                "IRP_MN_QUERY_BUS_INFORMATION",
 
                "IRP_MN_DEVICE_USAGE_NOTIFICATION",
 
                "IRP_MN_SURPRISE_REMOVAL",
 
                "IRP_MN_QUERY_LEGACY_BUS_INFORMATION",
 
        };
 
 
 
        if (fcn < arraysize(pnpname))
 
                KdPrint(("PCIVMEDispatchPnp  - IRP_MJ_PNP (%s)\n", pnpname[fcn]));
 
        else
 
                KdPrint(( "PCIVMEDispatchPnp - IRP_MJ_PNP (%2.2X)\n", fcn));
 
 
 
        static NTSTATUS(*fcntab[])(PDEVICE_OBJECT, PIRP) = {
 
                HandleStartDevice,        // IRP_MN_START_DEVICE
 
        //      DefaultPnpHandler,        // IRP_MN_QUERY_REMOVE_DEVICE
 
                HandleStopDevice          // IRP_MN_REMOVE_DEVICE
 
        };
 
 
 
        if (fcn >= arraysize(fcntab))
 
                return DefaultPnpHandler(fdo, Irp);
 
        return (*fcntab[fcn])(fdo, Irp);
 
}
 
 
 
 
 
NTSTATUS PCIVMEStartDevice(PDEVICE_OBJECT device_object, PIRP irp){
 
        NTSTATUS result = STATUS_SUCCESS;
 
        int            nPCIADAs;                                // count of PCIADAs
 
        DEVICE_EXT     *DeviceExtension = NULL;
 
        DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
 
        // init pciada structures ------------------------------------
 
        PCIVMESoftInit(device_object);
 
 
 
        // search for PCIADAs ----------------------------------------
 
        result = SearchDevices(device_object);
 
        nPCIADAs = DeviceExtension->nPCIADAs;
 
 
 
        if ((result != STATUS_SUCCESS) || !(nPCIADAs))
 
        {
 
                KdPrint(("PCIVMEStartDevice Device not found\n"));
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
 
 
        // request exclusive ownership of .. ---------------------------------
 
        if ((result = PCIVMEReserveResources(device_object, irp)) != STATUS_SUCCESS)
 
        {
 
                KdPrint(("PCIVMEStartDevice Resource not reserved PCIVMEReserveResources \n"));
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return result;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
        // fix PLX9050 Bug -------------------------------------------
 
        if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
 
        {
 
                KdPrint(("PCIVMEStartDevice PLX9050BugFix\n"));
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return result;
 
        }
 
 
 
        DeviceExtension->nInitState += 2;
 
        /*
 
        // translate BUS relative addresses ----------------------------------
 
        if ((result = PCIVMETranslateBusAddresses(device_object,irp)) != STATUS_SUCCESS)
 
        {
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        
 
        // translate Interrupt Resources used --------------------------------
 
        if ((result = PCIVMETranslateInterrupts(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
        */
 
 
 
        // map address spaces to virtual addresses ---------------------------
 
        if ((result = PCIVMEMapIOspace(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // initialze my custom DPC objects -----------------------------------
 
        if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return result;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // initialze the queue for IRPs waiting for vectors ------------------
 
        if ((result = InitializeIRPQueue(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return result;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // connect interrupts to service routines ----------------------------
 
        if ((result = PCIVMEConnectInterrupt(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // scan all connected VMEMM for info and later use -------------------
 
        if ((result = PCIVMEScanVMEMM(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCIVMEUnload(DeviceExtension->driverObj);
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
 
 
        device_object->Flags &= ~DO_DEVICE_INITIALIZING;
 
        return result;
 
}
 
 
 
NTSTATUS PCIVMEAddDevice(PDRIVER_OBJECT driverObj,  PDEVICE_OBJECT  pdo)
 
        {                                                       // AddDevice
 
        
 
        UNICODE_STRING device_name;
 
        UNICODE_STRING symbol_name;
 
        NTSTATUS result = STATUS_SUCCESS;
 
        //int            nPCIADAs;                              // count of PCIADAs
 
        DEVICE_EXT     *DeviceExtension = NULL;
 
        PDEVICE_OBJECT device_object;
 
        RtlInitUnicodeString(&device_name, L"\\Device\\PCIVME");
 
        KdPrint(("PCIVME AddDevice() v%d.%d\n", (DRIVER_VERSION >> 16) & 0xff, DRIVER_VERSION & 0xff));
 
        /* DeviceObject durch IO-Manager erzeugen */
 
        result = IoCreateDevice( driverObj,           // DriverObject received by the DriverEntry Call
 
                                                         sizeof(DEVICE_EXT),  // required Memory for the DeviceExtension
 
                                                         &device_name,        // Name of the device in the device-Directory
 
                                                         FILE_DEVICE_UNKNOWN, // Device-ID              
 
                                                         0,                   // Device-Characteristics normal 0
 
                                                         FALSE,               // TRUE : one Thread can open the driver
 
                                                         &device_object);     // DeviceObject returned from the IO-Manager
 
 
 
        // defines how the data are handled between user / kernel Adress-Space  
 
        device_object->Flags |= DO_DIRECT_IO;
 
 
 
#if 0
 
        // register the shutdown notification entry
 
    IoRegisterShutdownNotification(device_object);
 
#endif
 
 
 
        // anounce driver as symbolic device ---------------------------------
 
        if (result == STATUS_SUCCESS)
 
        {
 
                /* now the symbolic Link is created. If there is no S.L. a program cannot connect to the driver */
 
                RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
 
                result = IoCreateSymbolicLink(&symbol_name,&device_name);
 
                if (result != STATUS_SUCCESS)
 
                {
 
        
 
                        IoDeleteDevice(device_object);
 
                        return result;
 
                }
 
        }
 
        else
 
                return result;
 
 
 
 
 
        DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
 
 
 
        DeviceExtension->actualIrp  = NULL;
 
        DeviceExtension->driverObj  = driverObj;
 
        DeviceExtension->nInitState = 0;
 
 
 
        
 
        DeviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack(device_object, pdo);
 
    KdPrint(("AddDevice() OK.\n"));
 
 
 
        return result;
 
}
 
 
 
//------------------------------------------------------------------------
 
// the ultimate starting point of a driver
 
NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
 
{
 
        UNREFERENCED_PARAMETER(regPath);
 
        
 
        KdPrint(("PCIVME DriverEntry() v%d.%d\n", (DRIVER_VERSION >> 16) & 0xff, DRIVER_VERSION & 0xff));
 
 
 
        driverObj->DriverUnload = PCIVMEUnload;
 
        driverObj->DriverExtension->AddDevice = PCIVMEAddDevice;
 
        driverObj->MajorFunction[IRP_MJ_CREATE] = PCIVMEOpen;
 
        driverObj->MajorFunction[IRP_MJ_CLOSE] = PCIVMEClose;
 
        driverObj->MajorFunction[IRP_MJ_READ] = PCIVMERead;
 
        driverObj->MajorFunction[IRP_MJ_WRITE] = PCIVMEWrite;
 
        driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PCIVMEDeviceControl;
 
#ifdef DO_CLEANUP
 
        driverObj->MajorFunction[IRP_MJ_CLEANUP] = PCIVMECancel;
 
#endif
 
        driverObj->MajorFunction[IRP_MJ_SHUTDOWN] = PCIVMEShutdown;
 
        driverObj->MajorFunction[IRP_MJ_PNP] = PCIVMEDispatchPnp;
 
        return  STATUS_SUCCESS;;
 
}