Subversion Repositories f9daq

Rev

Blame | Last modification | View Log | RSS feed

//-------------------------------------------------------------------------
// 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
          if (*n == tolower(*ptr))     
          {
                  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  = 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)
{
    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 *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));
        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 *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));
        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;

    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;
}