//-------------------------------------------------------------------------
 
// WINNT driver for PCICC32 (CAMAC) interface of ARW Elektronik, Germany --
 
// the main body of the driver
 
//
 
// (c) 2000-2002 ARW Elektronik
 
//
 
// this source code is published under GPL (Open Source). You can use, redistribute 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
 
//
 
// what                                            who          when
 
// started out of pcivme sources                   AR           25.03.2000
 
// added IRQ handling                              AR           24.02.2001
 
// Added AUTOREAD functionality                    AR           17.03.2001
 
// Added LCR_READ                                  AR           31.03.2001
 
// resource allocation registers idle entries too  AR           25.11.2001
 
// changed making procedure (only VCC > 6.0)       AR           30.05.2002
 
// totally rearanged resource alloc for WIN2000    AR           01.06.2002
 
// version 2.14 eleminates PLXBUG in WIN2000       AR           05.06.2002
 
// added KeSynchronizeExecution for interrupt sync AR           16.06.2002
 
//
 
 
 
//------------------------------------------------------------------------
 
// DEFINES
 
//
 
#ifndef DWORD
 
#define DWORD ULONG
 
#endif
 
 
 
#ifndef WORD
 
#define WORD USHORT
 
#endif
 
 
 
#define CTL_INDEX(x) ((x >> 2) & 0xFF)  // get user control code as index
 
#define RESOURCE_ENTRY_COUNT 6          // WIN2000 forces to claim all entries
 
 
 
#define DOS_DEVICE_NAME L"\\DosDevices\\PCICC32:"
 
 
 
//-------------------------------------------------------------------------
 
// INCLUDES
 
//
 
  
 
#include <ntddk.h>
 
#include <devioctl.h>
 
// #include <wdm.h>
 
 
 
#include <pcicc32_drv.h>
 
#include <pcicc32.h>
 
#include <pcicc32_v.h>
 
#include <pcicc32_i.h>
 
#include <pcicc32_io.h>
 
 
 
 
 
//------------------------------------------------------------------------
 
// TYPEDEFS
 
//
 
typedef struct
 
{
 
        FILE_OBJ  *file_obj;
 
        PCIADA    *pciada;
 
        PVOID     pOutputBuffer;
 
        PVOID     pInputBuffer;
 
        ULONG     Address;
 
        DWORD     Length;
 
} SYNC_CONTEXT;
 
 
 
//------------------------------------------------------------------------
 
// GLOBALS
 
//
 
 
 
//------------------------------------------------------------------------
 
// FUNCTIONS
 
//
 
 
 
//------------------------------------------------------------------------
 
// for debug only - print interrupt line
 
//
 
#if DBG
 
void PrintInterruptLine(int Bus, int Slot)
 
{
 
  PCI_COMMON_CONFIG pci_config; 
 
 
 
  HalGetBusData( PCIConfiguration,                      // Bustype 
 
                                 Bus,                                   // PCI-Busnumber
 
                         Slot,                                          // Slotnumber
 
                                 (PVOID) &(pci_config),     // Pointer for the PCI-Information
 
                                 sizeof(PCI_COMMON_CONFIG));
 
 
 
  KdPrint(("Irql: %d\n", pci_config.u.type0.InterruptLine));
 
}
 
#endif
 
 
 
//------------------------------------------------------------------------
 
// get the cc32 number out of the filename
 
//
 
NTSTATUS InterpreteFileName(PCHAR name, int *nCC32)
 
{
 
        char *ptr = name;
 
    char *n   = "cc32_";
 
        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;
 
 
 
        *nCC32 = (h * 10) + l;  // calculate number
 
 
 
        if (*nCC32 >= PCICC32_MAX_CC32) // out of range ??
 
                  return STATUS_NO_SUCH_FILE;
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// the ultimate driver unload
 
VOID PCICC32Unload(PDRIVER_OBJECT driverObj)
 
{
 
        int              i; 
 
        UNICODE_STRING symbol_name;
 
        DEVICE_EXT *ext = (DEVICE_EXT*)(driverObj->DeviceObject->DeviceExtension);
 
        int         nPCIADAs = ext->nPCIADAs;
 
        PCIADA      *pciada;
 
 
 
    KdPrint(("PCICC32Unload()\n"));
 
 
 
        switch (ext->nInitState)
 
        {
 
                case 8:
 
                case 7:
 
                case 6: 
 
                        // stop interrupts and shut off
 
                        PCICC32DeInitPCIADAs(driverObj->DeviceObject);
 
                        PCICC32DisConnectInterrupt(driverObj->DeviceObject);
 
                case 5:
 
                        // KeInitializeDpc has no counterpart
 
                case 4:
 
                        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:
 
                        PCICC32FreeResources(driverObj->DeviceObject);
 
                default:
 
                case 0:
 
                        RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
 
 
 
                        // delete the symbolicLink in the registry 
 
                        IoDeleteSymbolicLink( &symbol_name);
 
 
 
                        // delete the deviceObject 
 
                        IoDeleteDevice(driverObj->DeviceObject);
 
        }
 
 
 
        KdPrint(("PCICC32Unload() OK.\n"));
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// called at CreateFile()
 
NTSTATUS PCICC32Open(PDEVICE_OBJECT deviceObj, PIRP Irp)
 
{
 
        NTSTATUS result = STATUS_SUCCESS;
 
    ANSI_STRING name;
 
    int nCC32;
 
        int i;
 
        DEVICE_EXT      *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
 
        PCIADA      *pciada;
 
        FILE_OBJ        *file_obj;
 
 
 
        name.Buffer = NULL;
 
    name.MaximumLength = 80;
 
 
 
        result = RtlUnicodeStringToAnsiString(&name, &(Irp->Tail.Overlay.OriginalFileObject->FileName), TRUE);
 
        if (result != STATUS_SUCCESS) goto fin;
 
 
 
        KdPrint(("PCICC32Open(%s)\n", name.Buffer));
 
 
 
        result = InterpreteFileName(name.Buffer, &nCC32);
 
    if (result != STATUS_SUCCESS) goto fin;
 
 
 
    KdPrint(("PCICC32Open(%d)\n", nCC32));
 
        RtlFreeAnsiString(&name);
 
 
 
    file_obj = (FILE_OBJ *)ExAllocatePool(NonPagedPool, sizeof(FILE_OBJ));
 
        if (file_obj == (FILE_OBJ *)NULL)
 
        {
 
                result = STATUS_NO_MEMORY;
 
                goto fin;
 
        }
 
 
 
        file_obj->uwAssociatedCC32  = (USHORT) nCC32;
 
 
 
    Irp->Tail.Overlay.OriginalFileObject->FsContext = (PVOID)file_obj;
 
 
 
        result = PCICC32ScanCC32(deviceObj);
 
        if (result != STATUS_SUCCESS) goto fin;
 
 
 
        for (i = 0; i < pDevExt->nPCIADAs; i++)
 
        {
 
          pciada = &pDevExt->pciada[i];
 
 
 
          if (pciada->wModuleNumber == nCC32) 
 
          {
 
                  pDevExt->cc32[nCC32] = pciada; // create association
 
                  pciada->dwLinkCount++;
 
 
 
                  enableCC32(pciada);
 
                  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);
 
 
 
        return result;
 
}
 
 
 
//------------------------------------------------------------------------
 
// called at close()
 
NTSTATUS PCICC32Close(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(("PCICC32Close(%d)\n", file_obj->uwAssociatedCC32));
 
 
 
        if (file_obj != (FILE_OBJ *)NULL)
 
        {
 
                pciada = pDevExt->cc32[file_obj->uwAssociatedCC32];
 
                pciada->dwLinkCount--;
 
 
 
                // disable interrupts when closing
 
                if (pciada->pIrqControlFile == file_obj)
 
                {
 
                        pciada->pIrqControlFile = (FILE_OBJ *)NULL;
 
                        globalInterruptDisable(pciada);
 
                }
 
 
 
                // cancel any blocking Irp origin from this file
 
                if (file_obj->blockingIrp != (PIRP)NULL)
 
                        file_obj->blockingIrp = (PIRP)NULL;
 
 
 
                if (pciada->pBlockingIrp == &file_obj->blockingIrp)
 
                        pciada->pBlockingIrp = (PIRP *)NULL;
 
 
 
                if (!pciada->dwLinkCount)
 
                          disableCC32(pciada);
 
                
 
                ExFreePool(file_obj);
 
                Irp->Tail.Overlay.OriginalFileObject->FsContext = (FILE_OBJ *)NULL;
 
        }
 
 
 
        KdPrint(("PCICC32Close OK\n"));
 
 
 
    Irp->IoStatus.Status = STATUS_SUCCESS;
 
        Irp->IoStatus.Information = 0;
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT);
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// called at 
 
NTSTATUS PCICC32Shutdown(PDEVICE_OBJECT deviceObj, PIRP irp)
 
{
 
        UNREFERENCED_PARAMETER(irp);
 
        KdPrint(("PCICC32Shutdown()\n"));
 
 
 
        // deinit interfaces and interrupts
 
        PCICC32DeInitPCIADAs(deviceObj);
 
 
 
    KdPrint(("PCICC32Shutdown() OK\n"));
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// called at ioctl()
 
NTSTATUS PCICC32DeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
 
{
 
        PIO_STACK_LOCATION IrpStack;
 
        int   nIndex;
 
 
 
        IrpStack  = IoGetCurrentIrpStackLocation(Irp);
 
        nIndex    = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
 
 
 
    KdPrint(("PCICC32DeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
 
 
 
        if (nIndex > CTL_INDEX(PCICC32_LAST_CTL_CODE))
 
        {
 
                KdPrint(("LastIndex(%d)\n", CTL_INDEX(PCICC32_LAST_CTL_CODE)));
 
                Irp->IoStatus.Status      = STATUS_UNSUCCESSFUL;
 
                Irp->IoStatus.Information = 0;
 
                IoCompleteRequest(Irp,IO_NO_INCREMENT);
 
 
 
        KdPrint(("PCICC32DeviceControl() FAIL.\n"));
 
 
 
                return STATUS_UNSUCCESSFUL;
 
        }
 
 
 
        return ioctl[nIndex](deviceObj, Irp, IrpStack);
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// called at read()
 
static BOOLEAN PCICC32Read_kernel(PVOID pvContext)
 
{
 
        register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
 
        register ULONG i = 0;
 
        USHORT   wCntrl;
 
 
 
        wCntrl = READ_REGISTER_USHORT(context->pciada->pwCntrl);
 
        if (context->file_obj->wBlockTransfer & AUTOREAD)
 
        {
 
                wCntrl &= ~0x0004;  // enable autoread - set bit to 0
 
                WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);                                
 
        }
 
 
 
        // do the read ---
 
        if (context->file_obj->wBlockTransfer & UNTIL_NOT_Q)
 
        {
 
                // read first time to get Q information
 
                register ULONG tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address);
 
 
 
                if (context->file_obj->wAccessType == WORD_ACCESS)
 
                {
 
                        PUSHORT pwBuffer = (PUSHORT)context->pOutputBuffer;
 
                        PUSHORT pwBufEnd = (PUSHORT)((PUCHAR)context->pOutputBuffer + context->Length);
 
 
 
                        while ((tempBuffer & 0x80000000) && (pwBuffer < pwBufEnd))
 
                        {
 
                                *pwBuffer++ = (USHORT)tempBuffer; 
 
                                tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address);  // read the same address multiple times as long to get Q
 
                                i++;
 
                        }
 
                }
 
                else 
 
                {
 
                        // LONG_ACCESS
 
                        PULONG pdwBuffer = (PULONG)context->pOutputBuffer;
 
                        PULONG pdwBufEnd = (PULONG)((PUCHAR)context->pOutputBuffer + context->Length);
 
 
 
                        while ((tempBuffer & 0x80000000) && (pdwBuffer < pdwBufEnd))
 
                        {
 
                                *pdwBuffer++ = tempBuffer; 
 
                                tempBuffer   = READ_REGISTER_ULONG((ULONG *)context->Address);  // read the same address multiple times as long to get Q
 
                                i++;
 
                        }
 
                }
 
 
 
                i *= context->file_obj->wAccessType;
 
 
 
                KdPrint(("UNTIL_NOT_Q, 0x%08x bytes read\n", i));
 
        }
 
        else // no UNTIL_NOT_Q
 
        {
 
                while (i < context->Length)
 
                {
 
                        context->file_obj->fRead((void *)((PUCHAR)context->pOutputBuffer + i), (void *)context->Address);  // read the same address multiple times
 
                        i += context->file_obj->wAccessType;
 
                }
 
        }
 
 
 
        // disable autoread unconditionally - set bit to 1
 
        wCntrl |= 0x0004;  
 
        WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);
 
 
 
    context->Length = i;        
 
 
 
        return TRUE;
 
}
 
 
 
NTSTATUS PCICC32Read(PDEVICE_OBJECT device_Obj, PIRP Irp)
 
{
 
        NTSTATUS        Status        = STATUS_SUCCESS;
 
        PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
 
        DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
        SYNC_CONTEXT context;
 
    
 
        context.file_obj              = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        context.pciada                = pDevExt->cc32[context.file_obj->uwAssociatedCC32]; 
 
        context.pOutputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
 
        context.Address           = IrpStack->Parameters.Read.ByteOffset.LowPart;   
 
        context.Length            = 0;
 
 
 
        KdPrint(("PCICC32Read(%d)\n", context.file_obj->uwAssociatedCC32));
 
 
 
        if (context.Address > IFR_SPACE)
 
                Status = STATUS_ACCESS_VIOLATION;
 
        else
 
        {
 
                // do here in between what has to be done -----------------
 
                context.Length = IrpStack->Parameters.Read.Length;
 
                KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
 
                context.Address = (ULONG)context.pciada->pvVirtIfr + context.Address;
 
 
 
                KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Read_kernel, &context);
 
                // do here in between what has to be done end -------------
 
        }
 
 
 
        Irp->IoStatus.Status      = Status;  
 
        Irp->IoStatus.Information = context.Length;  
 
        IoCompleteRequest(Irp,IO_NO_INCREMENT);  
 
 
 
    KdPrint(("PCICC32Read(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// called at write()
 
static BOOLEAN PCICC32Write_kernel(PVOID pvContext)
 
{
 
        register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
 
        register ULONG i = 0;
 
 
 
        // do the write ---
 
        while (i < context->Length)
 
        {
 
                context->file_obj->fWrite((void *)context->Address, (void *)((PUCHAR)context->pInputBuffer + i));  // write the same address multiple times
 
                i += context->file_obj->wAccessType;
 
        }
 
 
 
        context->Length = i;
 
 
 
        return TRUE;
 
}
 
 
 
NTSTATUS PCICC32Write(PDEVICE_OBJECT device_Obj, PIRP Irp)
 
{
 
        NTSTATUS        Status        = STATUS_SUCCESS;
 
        PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
 
        DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
        SYNC_CONTEXT context;
 
    
 
        context.file_obj              = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        context.pciada                = pDevExt->cc32[context.file_obj->uwAssociatedCC32]; 
 
        context.pInputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
 
        context.Address           = IrpStack->Parameters.Read.ByteOffset.LowPart;   
 
        context.Length            = 0;
 
 
 
        KdPrint(("PCICC32Write(%d)\n", context.file_obj->uwAssociatedCC32));
 
 
 
        if (context.Address > IFR_SPACE)
 
                Status = STATUS_ACCESS_VIOLATION;
 
        else
 
        {
 
//              register ULONG i = 0;
 
 
 
                // do here in between what has to be done -----------------
 
                context.Length    = IrpStack->Parameters.Read.Length;
 
                KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
 
                context.Address   = (ULONG)context.pciada->pvVirtIfr + context.Address;
 
 
 
                KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Write_kernel, &context);
 
                // do here in between what has to be done end -------------
 
        }
 
 
 
 
 
        Irp->IoStatus.Status      = Status;  
 
        Irp->IoStatus.Information = context.Length;  
 
        IoCompleteRequest(Irp,IO_NO_INCREMENT);  
 
 
 
    KdPrint(("PCICC32Write(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
} 
 
 
 
//------------------------------------------------------------------------
 
// search for pciada's
 
//
 
NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
 
{
 
  PCI_SLOT_NUMBER   SlotNumber;
 
  PCI_COMMON_CONFIG pci_config; 
 
  PCIADA            *pciada;
 
  ULONG             length;
 
  int               *found;
 
  int               i,j,k;
 
 
 
  KdPrint(("SearchDevices()\n"));
 
 
 
  // prepare structures ----------------------------------------
 
  found  = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
 
  *found = 0;
 
  for (i = 0; i < PCICC32_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;
 
 
 
  for (j = 0; j < PCI_MAX_BUSES; j++)
 
  {
 
    for (i = 0; i < PCI_MAX_DEVICES; i++)
 
        {
 
          SlotNumber.u.bits.DeviceNumber = i;
 
          for (k = 0; k < PCI_MAX_FUNCTION; k++)
 
          {
 
                SlotNumber.u.bits.FunctionNumber = k;
 
            length = HalGetBusData( PCIConfiguration,         // Bustype 
 
                                                            j,                                    // PCI-Busnumber
 
                                                            SlotNumber.u.AsULONG,     // Slotnumber
 
                                                            (PVOID) &(pci_config),    // Pointer for the PCI-Information
 
                                                            sizeof(PCI_COMMON_CONFIG) );
 
 
 
                if ((pci_config.VendorID    == PCICC32_VENDOR_ID) &&
 
                        (pci_config.DeviceID    == PCICC32_DEVICE_ID) &&
 
                        (pci_config.u.type0.SubSystemID == PCICC32_SUBSYS_ID) &&
 
                        (pci_config.u.type0.SubVendorID == PCICC32_SUBVEN_ID) &&
 
                        (pci_config.u.type0.BaseAddresses[3]))
 
                {
 
               pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found]; 
 
 
 
               memcpy(&pciada
->PCIDevice
, &pci_config
, sizeof(pci_config
));  
                   pciada->Slot = SlotNumber;
 
                   pciada->Bus  = j;
 
 
 
                   KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
 
 
 
                   (*found)++;
 
                   if (*found >= PCICC32_MAX_PCIADA) return STATUS_SUCCESS;
 
                }
 
          }
 
        }               
 
  }
 
 
 
  return STATUS_SUCCESS;
 
}
 
 
 
//---------------------------------------------------------------
 
// function to call for bug fix of PLX9050 build in bug
 
//
 
NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
 
{
 
        DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
 
        int i;
 
        ULONG dwData;
 
        PCIADA *pciada;
 
 
 
        KdPrint(("PLX9050BugFix()\n"));
 
 
 
        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 (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus, 
 
                                  pciada->Slot.u.AsULONG, 
 
                                        (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0],
 
                                                0x10, 4) != 4)
 
                        return STATUS_UNSUCCESSFUL;
 
 
 
                        if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus, 
 
                                  pciada->Slot.u.AsULONG, 
 
                                        (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 (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus, 
 
                                  pciada->Slot.u.AsULONG, 
 
                                        (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1],
 
                                                0x14, 4) != 4)
 
                        return STATUS_UNSUCCESSFUL;
 
 
 
                  if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus, 
 
                                  pciada->Slot.u.AsULONG, 
 
                                        (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5],
 
                                                0x24, 4) != 4)
 
                        return STATUS_UNSUCCESSFUL;
 
                }
 
        }
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
//  reserve resources for PCIADAs 
 
//
 
NTSTATUS PCICC32ExtractResources(PCIADA *pciada, PCM_RESOURCE_LIST pList) 
 
{
 
        PCM_RESOURCE_LIST pResourceList;
 
        PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
 
        PCM_PARTIAL_RESOURCE_LIST pPartialList;
 
        PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
 
        int i;
 
        int bug = 0;
 
 
 
        KdPrint(("PCICC32ExtractResources()\n"));
 
 
 
        pResourceList   = pList;
 
        pFullDescriptor = pResourceList->List;
 
        pPartialList    = &pFullDescriptor->PartialResourceList;
 
 
 
        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(("Irq    : Irql: %d, Vector: %d, Affinity: %d\n", 
 
                                        pciada->Irql, pciada->Vector, pciada->Affinity));
 
                                break;
 
                        case CmResourceTypeDma:
 
                                KdPrint(("Dma    : \n")); 
 
                                break;
 
                        case CmResourceTypePort:
 
 
 
                                KdPrint(("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 (i == 0)
 
                                        {
 
                                                pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
 
 
 
                                                if (pciada->pvPhysLcr.LowPart & 0x80) 
 
                                                        bug = 1;
 
                                        }
 
                                }
 
                                else
 
                                {
 
                                        if (i == 3)
 
                                                pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
 
                                }
 
 
 
                                if (i == 2)
 
                                        pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
 
 
 
                                KdPrint(("Memory : 0x%p\n", (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart)); 
 
                                break;
 
                }
 
        }
 
 
 
        if (pciada->Irql == 0)
 
                return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
 
 
 
        KdPrint(("PCICC32ExtractResources() OK.\n"));
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
NTSTATUS PCICC32ReserveResources(PDEVICE_OBJECT device_Obj)
 
{
 
        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(("PCICC32ReserveResources()\n"));
 
 
 
        // prepare resource claiming
 
        RtlInitUnicodeString(&DriverClassName, L"PCICC32");
 
 
 
        // 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);
 
 
 
                if (result != STATUS_SUCCESS)
 
                        break;
 
 
 
                result = PCICC32ExtractResources(pciada, pList);
 
 
 
                if (result != STATUS_SUCCESS)
 
                        break;
 
        }
 
 
 
        // its my part to free allocated resources
 
        ExFreePool(pList);
 
 
 
        KdPrint(("PCICC32ReserveResources(0x%08x)\n", result));
 
 
 
        return result;
 
};
 
 
 
//------------------------------------------------------------------------
 
//  free resources from PCIADAs 
 
//
 
NTSTATUS PCICC32FreeResources(PDEVICE_OBJECT device_Obj)
 
{
 
        CM_RESOURCE_LIST ResList;
 
        BOOLEAN          bConflict;
 
    UNICODE_STRING   DriverClassName;
 
 
 
    KdPrint(("PCICC32FreeResources()\n"));
 
 
 
        RtlInitUnicodeString(&DriverClassName, L"PCICC32");
 
 
 
        ResList.Count = 0;
 
 
 
        IoReportResourceUsage(&DriverClassName, device_Obj->DriverObject, 
 
                                         &ResList, sizeof(ResList), device_Obj, 
 
                                                                         NULL, 0, FALSE, &bConflict);
 
        return STATUS_SUCCESS;
 
};
 
 
 
 
 
//------------------------------------------------------------------------
 
//  translate memory resources to neutral for PCIADAs 
 
//
 
NTSTATUS PCICC32TranslateBusAddresses(PDEVICE_OBJECT device_Obj)
 
{
 
        int              i;
 
        NTSTATUS         result = STATUS_SUCCESS;
 
        int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
 
        ULONG            memType0, memType2;
 
        PCIADA           *pciada;
 
 
 
    KdPrint(("TranslateBusAddresseses()\n"));
 
        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;
 
          }
 
 
 
          if ((memType0) || (memType2))
 
          {
 
                  result = STATUS_UNSUCCESSFUL;
 
                  break;
 
          }
 
        }
 
        return result;
 
}
 
 
 
//------------------------------------------------------------------------
 
//  map address spaces to virtual addresses
 
//
 
NTSTATUS PCICC32MapIOspaces(PDEVICE_OBJECT device_Obj)
 
{
 
        int              i;
 
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
 
        int                              nPCIADAs = pDevExt->nPCIADAs;
 
        PCIADA           *pciada;
 
 
 
        KdPrint(("PCICC32MapIOspaces()\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;
 
        DEVICE_EXT       *pDevExt = (DEVICE_EXT*)(device_object->DeviceExtension);
 
        int              nPCIADAs = pDevExt->nPCIADAs;
 
        PCIADA           *pciada;
 
 
 
        KdPrint(("InitializeCustomDPCObject()\n"));
 
 
 
        for (i = 0; i < nPCIADAs; i++)
 
        {
 
                pciada = &pDevExt->pciada[i];
 
                KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
 
        }
 
 
 
        return STATUS_SUCCESS;
 
}
 
 
 
//------------------------------------------------------------------------
 
// init structures a.s.o.
 
//
 
VOID PCICC32SoftInit(PDEVICE_OBJECT device_Obj)
 
{
 
        int i;
 
        PCIADA *pciada;
 
 
 
        for (i = 0; i < PCICC32_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->wModuleNumber  = 0xFFFF;
 
                pciada->wFPGAVersion   = 0xFFFF;
 
                pciada->wModuleType    = 1;       // always CC32
 
 
 
                pciada->InterruptObject = NULL;
 
                pciada->Irql                    = 0;
 
                pciada->Vector          = 0;
 
                pciada->Affinity                = 0;
 
 
 
                pciada->dwLinkCount     = 0;
 
 
 
                pciada->dwIrqStatus     = 0;
 
                pciada->pBlockingIrp    = (PIRP *)NULL;
 
 
 
                pciada->pIrqControlFile = (FILE_OBJ *)NULL;
 
        }
 
 
 
        // no CC32 associated to any PCIADA
 
        for (i = 0; i < PCICC32_MAX_CC32; i++)
 
          ((DEVICE_EXT*)(device_Obj->DeviceExtension))->cc32[i] = NULL;
 
}
 
 
 
//------------------------------------------------------------------------
 
// the ultimate starting point of a driver
 
NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
 
{
 
        int            i;
 
        PDEVICE_OBJECT device_object;                   // pointer to the device object
 
        UNICODE_STRING device_name;
 
        UNICODE_STRING symbol_name;
 
        NTSTATUS result = STATUS_SUCCESS;
 
        PCIADA         *pciada;                                 // pointer to a PCIADA
 
        int            nPCIADAs;                                // count of PCIADAs
 
        DEVICE_EXT     *DeviceExtension = NULL; 
 
        UNREFERENCED_PARAMETER(regPath);
 
    KdPrint(("DriverEntry() ----%d.%d-------------------------\n", (DRIVER_VERSION >> 16) & 0xFFFF, DRIVER_VERSION & 0xFFFF));
 
 
 
        driverObj->DriverUnload = PCICC32Unload;
 
        driverObj->MajorFunction[IRP_MJ_CREATE]            = PCICC32Open;
 
        driverObj->MajorFunction[IRP_MJ_CLOSE]             = PCICC32Close;
 
        driverObj->MajorFunction[IRP_MJ_READ]              = PCICC32Read;
 
    driverObj->MajorFunction[IRP_MJ_WRITE]             = PCICC32Write;
 
        driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]    = PCICC32DeviceControl;
 
    driverObj->MajorFunction[IRP_MJ_SHUTDOWN]          = PCICC32Shutdown;
 
 
 
        RtlInitUnicodeString(&device_name, L"\\Device\\CC32");
 
 
 
        /* 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;
 
 
 
        // 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->nInitState = 0;
 
 
 
        // init pciada structures ------------------------------------
 
        PCICC32SoftInit(device_object);
 
 
 
        // search for PCIADAs ----------------------------------------
 
        result   = SearchDevices(device_object);
 
        nPCIADAs = DeviceExtension->nPCIADAs;
 
 
 
        if ((result != STATUS_SUCCESS) || !(nPCIADAs))
 
        {
 
                PCICC32Unload(driverObj);     
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        } 
 
 
 
        // request exclusive ownership of .. ---------------------------------
 
        if ((result = PCICC32ReserveResources(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return result;
 
        } 
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // fix PLX9050 Bug -------------------------------------------
 
        if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return result;
 
        }
 
 
 
        // translate BUS relative addresses ----------------------------------
 
        if ((result = PCICC32TranslateBusAddresses(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        } 
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // translate Interrupt Resources used --------------------------------
 
        if ((result = PCICC32TranslateInterrupt(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
        
 
        // map address spaces to virtual addresses ---------------------------
 
        if ((result = PCICC32MapIOspaces(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        } 
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // initialze my custom DPC objects -----------------------------------
 
        if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return result;
 
        } 
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // disable all interrupts --------------------------------------------
 
        for (i = 0; i < nPCIADAs; i++)
 
        {
 
                pciada = &DeviceExtension->pciada[i];
 
 
 
                globalInterruptDisable(pciada);
 
        }
 
 
 
        // connect interrupts to service routines ----------------------------
 
        if ((result = PCICC32ConnectInterrupt(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        }
 
        else
 
                DeviceExtension->nInitState++;
 
 
 
        // scan all connected CC32 for info and later use -------------------
 
        if ((result = PCICC32ScanCC32(device_object)) != STATUS_SUCCESS)
 
        {
 
                PCICC32Unload(driverObj);     
 
                return STATUS_DEVICE_DOES_NOT_EXIST;
 
        } 
 
 
 
        device_object->Flags &= ~DO_DEVICE_INITIALIZING;
 
 
 
    KdPrint(("DriverEntry() OK.\n"));
 
 
 
        return result;
 
}