Subversion Repositories f9daq

Rev

Rev 23 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. //-------------------------------------------------------------------------
  2. // WINNT driver for PCICC32 (CAMAC) interface of ARW Elektronik, Germany --
  3. // the main body of the driver
  4. //
  5. // (c) 2000-2002 ARW Elektronik
  6. //
  7. // this source code is published under GPL (Open Source). You can use, redistribute and
  8. // modify it unless this header   is not modified or deleted. No warranty is given that
  9. // this software will work like expected.
  10. // This product is not authorized for use as critical component in life support systems
  11. // wihout the express written approval of ARW Elektronik Germany.
  12. //
  13. // Please announce changes and hints to ARW Elektronik
  14. //
  15. // what                                            who          when
  16. // started out of pcivme sources                   AR           25.03.2000
  17. // added IRQ handling                              AR           24.02.2001
  18. // Added AUTOREAD functionality                    AR           17.03.2001
  19. // Added LCR_READ                                  AR           31.03.2001
  20. // resource allocation registers idle entries too  AR           25.11.2001
  21. // changed making procedure (only VCC > 6.0)       AR           30.05.2002
  22. // totally rearanged resource alloc for WIN2000    AR           01.06.2002
  23. // version 2.14 eleminates PLXBUG in WIN2000       AR           05.06.2002
  24. // added KeSynchronizeExecution for interrupt sync AR           16.06.2002
  25. //
  26.  
  27. //------------------------------------------------------------------------
  28. // DEFINES
  29. //
  30. #ifndef DWORD
  31. #define DWORD ULONG
  32. #endif
  33.  
  34. #ifndef WORD
  35. #define WORD USHORT
  36. #endif
  37.  
  38. #define CTL_INDEX(x) ((x >> 2) & 0xFF)  // get user control code as index
  39. #define RESOURCE_ENTRY_COUNT 6          // WIN2000 forces to claim all entries
  40.  
  41. #define DOS_DEVICE_NAME L"\\DosDevices\\PCICC32:"
  42.  
  43. //-------------------------------------------------------------------------
  44. // INCLUDES
  45. //
  46.  
  47. #include <ntddk.h>
  48. #include <devioctl.h>
  49. // #include <wdm.h>
  50.  
  51. #include <pcicc32_drv.h>
  52. #include <pcicc32.h>
  53. #include <pcicc32_v.h>
  54. #include <pcicc32_i.h>
  55. #include <pcicc32_io.h>
  56.  
  57.  
  58. //------------------------------------------------------------------------
  59. // TYPEDEFS
  60. //
  61. typedef struct
  62. {
  63.         FILE_OBJ  *file_obj;
  64.         PCIADA    *pciada;
  65.         PVOID     pOutputBuffer;
  66.         PVOID     pInputBuffer;
  67.         ULONG     Address;
  68.         DWORD     Length;
  69. } SYNC_CONTEXT;
  70.  
  71. //------------------------------------------------------------------------
  72. // GLOBALS
  73. //
  74.  
  75. //------------------------------------------------------------------------
  76. // FUNCTIONS
  77. //
  78.  
  79. //------------------------------------------------------------------------
  80. // for debug only - print interrupt line
  81. //
  82. #if DBG
  83. void PrintInterruptLine(int Bus, int Slot)
  84. {
  85.   PCI_COMMON_CONFIG pci_config;
  86.  
  87.   HalGetBusData( PCIConfiguration,                      // Bustype
  88.                                  Bus,                                   // PCI-Busnumber
  89.                          Slot,                                          // Slotnumber
  90.                                  (PVOID) &(pci_config),     // Pointer for the PCI-Information
  91.                                  sizeof(PCI_COMMON_CONFIG));
  92.  
  93.   KdPrint(("Irql: %d\n", pci_config.u.type0.InterruptLine));
  94. }
  95. #endif
  96.  
  97. //------------------------------------------------------------------------
  98. // get the cc32 number out of the filename
  99. //
  100. NTSTATUS InterpreteFileName(PCHAR name, int *nCC32)
  101. {
  102.         char *ptr = name;
  103.     char *n   = "cc32_";
  104.         int  h = -1;  // high part
  105.         int  l = -1;  // low part
  106.  
  107.         if (*ptr == '\\') ptr++; // jump over leading ...
  108.  
  109.     while (*n)                           // compare the basename
  110.           if (*n == tolower(*ptr))     
  111.           {
  112.                   n++;
  113.                   ptr++;
  114.           }
  115.           else
  116.                   return STATUS_NO_SUCH_FILE;
  117.  
  118.         h = *ptr - '0';                  // get the number
  119.         ptr++;
  120.         l = *ptr - '0';
  121.  
  122.         if (*ptr == 0)                   // still over the end ??
  123.         {
  124.                 l = h;
  125.                 h = 0;
  126.         }
  127.         else
  128.           ptr++;
  129.  
  130.         if ((h < 0) || (l < 0) || (*ptr != 0))  // anything wrong ??
  131.                   return STATUS_NO_SUCH_FILE;
  132.  
  133.         *nCC32 = (h * 10) + l;  // calculate number
  134.  
  135.         if (*nCC32 >= PCICC32_MAX_CC32) // out of range ??
  136.                   return STATUS_NO_SUCH_FILE;
  137.  
  138.         return STATUS_SUCCESS;
  139. }
  140.  
  141. //------------------------------------------------------------------------
  142. // the ultimate driver unload
  143. VOID PCICC32Unload(PDRIVER_OBJECT driverObj)
  144. {
  145.         int              i;
  146.         UNICODE_STRING symbol_name;
  147.         DEVICE_EXT *ext = (DEVICE_EXT*)(driverObj->DeviceObject->DeviceExtension);
  148.         int         nPCIADAs = ext->nPCIADAs;
  149.         PCIADA      *pciada;
  150.  
  151.     KdPrint(("PCICC32Unload()\n"));
  152.  
  153.         switch (ext->nInitState)
  154.         {
  155.                 case 8:
  156.                 case 7:
  157.                 case 6:
  158.                         // stop interrupts and shut off
  159.                         PCICC32DeInitPCIADAs(driverObj->DeviceObject);
  160.                         PCICC32DisConnectInterrupt(driverObj->DeviceObject);
  161.                 case 5:
  162.                         // KeInitializeDpc has no counterpart
  163.                 case 4:
  164.                         for (i = 0; i < nPCIADAs; i++)
  165.                         {
  166.                                 pciada = &ext->pciada[i];
  167.                                 if (pciada->pvVirtLcr != NULL)
  168.                                         MmUnmapIoSpace(pciada->pvVirtLcr, LCR_SPACE);
  169.                                 if (pciada->pvVirtIfr != NULL)
  170.                                         MmUnmapIoSpace(pciada->pvVirtIfr, IFR_SPACE);
  171.                         }
  172.                 case 3:
  173.                         // HalGetInterruptVector has no counterpart
  174.                 case 2:
  175.                         // HalTranslateBusAddress has no counterpart
  176.                 case 1:
  177.                         PCICC32FreeResources(driverObj->DeviceObject);
  178.                 default:
  179.                 case 0:
  180.                         RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
  181.  
  182.                         // delete the symbolicLink in the registry
  183.                         IoDeleteSymbolicLink( &symbol_name);
  184.  
  185.                         // delete the deviceObject
  186.                         IoDeleteDevice(driverObj->DeviceObject);
  187.         }
  188.  
  189.         KdPrint(("PCICC32Unload() OK.\n"));
  190. }
  191.  
  192.  
  193. //------------------------------------------------------------------------
  194. // called at CreateFile()
  195. NTSTATUS PCICC32Open(PDEVICE_OBJECT deviceObj, PIRP Irp)
  196. {
  197.         NTSTATUS result = STATUS_SUCCESS;
  198.     ANSI_STRING name;
  199.     int nCC32;
  200.         int i;
  201.         DEVICE_EXT      *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
  202.         PCIADA      *pciada;
  203.         FILE_OBJ        *file_obj;
  204.  
  205.         name.Buffer = NULL;
  206.     name.MaximumLength = 80;
  207.  
  208.         result = RtlUnicodeStringToAnsiString(&name, &(Irp->Tail.Overlay.OriginalFileObject->FileName), TRUE);
  209.         if (result != STATUS_SUCCESS) goto fin;
  210.  
  211.         KdPrint(("PCICC32Open(%s)\n", name.Buffer));
  212.  
  213.         result = InterpreteFileName(name.Buffer, &nCC32);
  214.     if (result != STATUS_SUCCESS) goto fin;
  215.  
  216.     KdPrint(("PCICC32Open(%d)\n", nCC32));
  217.         RtlFreeAnsiString(&name);
  218.  
  219.     file_obj = (FILE_OBJ *)ExAllocatePool(NonPagedPool, sizeof(FILE_OBJ));
  220.         if (file_obj == (FILE_OBJ *)NULL)
  221.         {
  222.                 result = STATUS_NO_MEMORY;
  223.                 goto fin;
  224.         }
  225.  
  226.         file_obj->uwAssociatedCC32  = nCC32;
  227.  
  228.     Irp->Tail.Overlay.OriginalFileObject->FsContext = (PVOID)file_obj;
  229.  
  230.         result = PCICC32ScanCC32(deviceObj);
  231.         if (result != STATUS_SUCCESS) goto fin;
  232.  
  233.         for (i = 0; i < pDevExt->nPCIADAs; i++)
  234.         {
  235.           pciada = &pDevExt->pciada[i];
  236.  
  237.           if (pciada->wModuleNumber == nCC32)
  238.           {
  239.                   pDevExt->cc32[nCC32] = pciada; // create association
  240.                   pciada->dwLinkCount++;
  241.  
  242.                   enableCC32(pciada);
  243.                   break;
  244.           }
  245.         }
  246.  
  247.         if (i >= pDevExt->nPCIADAs)
  248.         {
  249.                 result = STATUS_NO_SUCH_FILE;
  250.                 goto fin;
  251.         }
  252.  
  253.         fin:
  254.         Irp->IoStatus.Status = result;
  255.         Irp->IoStatus.Information = 0;
  256.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
  257.  
  258.         return result;
  259. }
  260.  
  261. //------------------------------------------------------------------------
  262. // called at close()
  263. NTSTATUS PCICC32Close(PDEVICE_OBJECT deviceObj, PIRP Irp)
  264. {
  265.         DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(deviceObj->DeviceExtension);
  266.         FILE_OBJ    *file_obj = (FILE_OBJ *)NULL;
  267.         PCIADA      *pciada;                   
  268.  
  269.         file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  270.  
  271.     KdPrint(("PCICC32Close(%d)\n", file_obj->uwAssociatedCC32));
  272.  
  273.         if (file_obj != (FILE_OBJ *)NULL)
  274.         {
  275.                 pciada = pDevExt->cc32[file_obj->uwAssociatedCC32];
  276.                 pciada->dwLinkCount--;
  277.  
  278.                 // disable interrupts when closing
  279.                 if (pciada->pIrqControlFile == file_obj)
  280.                 {
  281.                         pciada->pIrqControlFile = (FILE_OBJ *)NULL;
  282.                         globalInterruptDisable(pciada);
  283.                 }
  284.  
  285.                 // cancel any blocking Irp origin from this file
  286.                 if (file_obj->blockingIrp != (PIRP)NULL)
  287.                         file_obj->blockingIrp = (PIRP)NULL;
  288.  
  289.                 if (pciada->pBlockingIrp == &file_obj->blockingIrp)
  290.                         pciada->pBlockingIrp = (PIRP *)NULL;
  291.  
  292.                 if (!pciada->dwLinkCount)
  293.                           disableCC32(pciada);
  294.                
  295.                 ExFreePool(file_obj);
  296.                 Irp->Tail.Overlay.OriginalFileObject->FsContext = (FILE_OBJ *)NULL;
  297.         }
  298.  
  299.         KdPrint(("PCICC32Close OK\n"));
  300.  
  301.     Irp->IoStatus.Status = STATUS_SUCCESS;
  302.         Irp->IoStatus.Information = 0;
  303.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
  304.  
  305.         return STATUS_SUCCESS;
  306. }
  307.  
  308. //------------------------------------------------------------------------
  309. // called at
  310. NTSTATUS PCICC32Shutdown(PDEVICE_OBJECT deviceObj, PIRP irp)
  311. {
  312.     KdPrint(("PCICC32Shutdown()\n"));
  313.  
  314.         // deinit interfaces and interrupts
  315.         PCICC32DeInitPCIADAs(deviceObj);
  316.  
  317.     KdPrint(("PCICC32Shutdown() OK\n"));
  318.  
  319.         return STATUS_SUCCESS;
  320. }
  321.  
  322. //------------------------------------------------------------------------
  323. // called at ioctl()
  324. NTSTATUS PCICC32DeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
  325. {
  326.         PIO_STACK_LOCATION IrpStack;
  327.         int   nIndex;
  328.  
  329.         IrpStack  = IoGetCurrentIrpStackLocation(Irp);
  330.         nIndex    = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
  331.  
  332.     KdPrint(("PCICC32DeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
  333.  
  334.         if (nIndex > CTL_INDEX(PCICC32_LAST_CTL_CODE))
  335.         {
  336.                 KdPrint(("LastIndex(%d)\n", CTL_INDEX(PCICC32_LAST_CTL_CODE)));
  337.                 Irp->IoStatus.Status      = STATUS_UNSUCCESSFUL;
  338.                 Irp->IoStatus.Information = 0;
  339.                 IoCompleteRequest(Irp,IO_NO_INCREMENT);
  340.  
  341.         KdPrint(("PCICC32DeviceControl() FAIL.\n"));
  342.  
  343.                 return STATUS_UNSUCCESSFUL;
  344.         }
  345.  
  346.         return ioctl[nIndex](deviceObj, Irp, IrpStack);
  347. }
  348.  
  349.  
  350. //------------------------------------------------------------------------
  351. // called at read()
  352. static BOOLEAN PCICC32Read_kernel(PVOID pvContext)
  353. {
  354.         register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
  355.         register ULONG i = 0;
  356.         USHORT   wCntrl;
  357.  
  358.         wCntrl = READ_REGISTER_USHORT(context->pciada->pwCntrl);
  359.         if (context->file_obj->wBlockTransfer & AUTOREAD)
  360.         {
  361.                 wCntrl &= ~0x0004;  // enable autoread - set bit to 0
  362.                 WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);                               
  363.         }
  364.  
  365.         // do the read ---
  366.         if (context->file_obj->wBlockTransfer & UNTIL_NOT_Q)
  367.         {
  368.                 // read first time to get Q information
  369.                 register ULONG tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address);
  370.  
  371.                 if (context->file_obj->wAccessType == WORD_ACCESS)
  372.                 {
  373.                         PUSHORT pwBuffer = (PUSHORT)context->pOutputBuffer;
  374.                         PUSHORT pwBufEnd = (PUSHORT)((PUCHAR)context->pOutputBuffer + context->Length);
  375.  
  376.                         while ((tempBuffer & 0x80000000) && (pwBuffer < pwBufEnd))
  377.                         {
  378.                                 *pwBuffer++ = (USHORT)tempBuffer;
  379.                                 tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address);  // read the same address multiple times as long to get Q
  380.                                 i++;
  381.                         }
  382.                 }
  383.                 else
  384.                 {
  385.                         // LONG_ACCESS
  386.                         PULONG pdwBuffer = (PULONG)context->pOutputBuffer;
  387.                         PULONG pdwBufEnd = (PULONG)((PUCHAR)context->pOutputBuffer + context->Length);
  388.  
  389.                         while ((tempBuffer & 0x80000000) && (pdwBuffer < pdwBufEnd))
  390.                         {
  391.                                 *pdwBuffer++ = tempBuffer;
  392.                                 tempBuffer   = READ_REGISTER_ULONG((ULONG *)context->Address);  // read the same address multiple times as long to get Q
  393.                                 i++;
  394.                         }
  395.                 }
  396.  
  397.                 i *= context->file_obj->wAccessType;
  398.  
  399.                 KdPrint(("UNTIL_NOT_Q, 0x%08x bytes read\n", i));
  400.         }
  401.         else // no UNTIL_NOT_Q
  402.         {
  403.                 while (i < context->Length)
  404.                 {
  405.                         context->file_obj->fRead((void *)((PUCHAR)context->pOutputBuffer + i), (void *)context->Address);  // read the same address multiple times
  406.                         i += context->file_obj->wAccessType;
  407.                 }
  408.         }
  409.  
  410.         // disable autoread unconditionally - set bit to 1
  411.         wCntrl |= 0x0004;  
  412.         WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);
  413.  
  414.     context->Length = i;       
  415.  
  416.         return TRUE;
  417. }
  418.  
  419. NTSTATUS PCICC32Read(PDEVICE_OBJECT device_Obj, PIRP Irp)
  420. {
  421.         NTSTATUS        Status        = STATUS_SUCCESS;
  422.         PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  423.         DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  424.         SYNC_CONTEXT context;
  425.    
  426.         context.file_obj              = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  427.         context.pciada                = pDevExt->cc32[context.file_obj->uwAssociatedCC32];
  428.         context.pOutputBuffer     = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));
  429.         context.Address           = IrpStack->Parameters.Read.ByteOffset.LowPart;  
  430.         context.Length            = 0;
  431.  
  432.         KdPrint(("PCICC32Read(%d)\n", context.file_obj->uwAssociatedCC32));
  433.  
  434.         if (context.Address > IFR_SPACE)
  435.                 Status = STATUS_ACCESS_VIOLATION;
  436.         else
  437.         {
  438.                 // do here in between what has to be done -----------------
  439.                 context.Length = IrpStack->Parameters.Read.Length;
  440.                 KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
  441.                 context.Address = (ULONG)context.pciada->pvVirtIfr + context.Address;
  442.  
  443.                 KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Read_kernel, &context);
  444.                 // do here in between what has to be done end -------------
  445.         }
  446.  
  447.         Irp->IoStatus.Status      = Status;  
  448.         Irp->IoStatus.Information = context.Length;  
  449.         IoCompleteRequest(Irp,IO_NO_INCREMENT);  
  450.  
  451.     KdPrint(("PCICC32Read(), Status = 0x%08x\n", Status));
  452.  
  453.         return Status;
  454. }
  455.  
  456.  
  457. //------------------------------------------------------------------------
  458. // called at write()
  459. static BOOLEAN PCICC32Write_kernel(PVOID pvContext)
  460. {
  461.         register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
  462.         register ULONG i = 0;
  463.  
  464.         // do the write ---
  465.         while (i < context->Length)
  466.         {
  467.                 context->file_obj->fWrite((void *)context->Address, (void *)((PUCHAR)context->pInputBuffer + i));  // write the same address multiple times
  468.                 i += context->file_obj->wAccessType;
  469.         }
  470.  
  471.         context->Length = i;
  472.  
  473.         return TRUE;
  474. }
  475.  
  476. NTSTATUS PCICC32Write(PDEVICE_OBJECT device_Obj, PIRP Irp)
  477. {
  478.         NTSTATUS        Status        = STATUS_SUCCESS;
  479.         PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  480.         DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  481.         SYNC_CONTEXT context;
  482.    
  483.         context.file_obj              = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  484.         context.pciada                = pDevExt->cc32[context.file_obj->uwAssociatedCC32];
  485.         context.pInputBuffer      = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));
  486.         context.Address           = IrpStack->Parameters.Read.ByteOffset.LowPart;  
  487.         context.Length            = 0;
  488.  
  489.         KdPrint(("PCICC32Write(%d)\n", context.file_obj->uwAssociatedCC32));
  490.  
  491.         if (context.Address > IFR_SPACE)
  492.                 Status = STATUS_ACCESS_VIOLATION;
  493.         else
  494.         {
  495.                 register ULONG i = 0;
  496.  
  497.                 // do here in between what has to be done -----------------
  498.                 context.Length    = IrpStack->Parameters.Read.Length;
  499.                 KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
  500.                 context.Address   = (ULONG)context.pciada->pvVirtIfr + context.Address;
  501.  
  502.                 KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Write_kernel, &context);
  503.                 // do here in between what has to be done end -------------
  504.         }
  505.  
  506.  
  507.         Irp->IoStatus.Status      = Status;  
  508.         Irp->IoStatus.Information = context.Length;  
  509.         IoCompleteRequest(Irp,IO_NO_INCREMENT);  
  510.  
  511.     KdPrint(("PCICC32Write(), Status = 0x%08x\n", Status));
  512.  
  513.         return Status;
  514. }
  515.  
  516. //------------------------------------------------------------------------
  517. // search for pciada's
  518. //
  519. NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
  520. {
  521.   PCI_SLOT_NUMBER   SlotNumber;
  522.   PCI_COMMON_CONFIG pci_config;
  523.   PCIADA            *pciada;
  524.   ULONG             length;
  525.   int               *found;
  526.   int               i,j,k;
  527.  
  528.   KdPrint(("SearchDevices()\n"));
  529.  
  530.   // prepare structures ----------------------------------------
  531.   found  = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
  532.   *found = 0;
  533.   for (i = 0; i < PCICC32_MAX_PCIADA; i++)
  534.   {
  535.         pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  536.  
  537.         pciada->Bus                = -1;
  538.     pciada->Slot.u.AsULONG     = 0xFFFFFFFF;
  539.   }
  540.  
  541.   // search for pciada's ---------------------------------------
  542.   SlotNumber.u.bits.Reserved = 0;
  543.  
  544.   for (j = 0; j < PCI_MAX_BUSES; j++)
  545.   {
  546.     for (i = 0; i < PCI_MAX_DEVICES; i++)
  547.         {
  548.           SlotNumber.u.bits.DeviceNumber = i;
  549.           for (k = 0; k < PCI_MAX_FUNCTION; k++)
  550.           {
  551.                 SlotNumber.u.bits.FunctionNumber = k;
  552.             length = HalGetBusData( PCIConfiguration,         // Bustype
  553.                                                             j,                                    // PCI-Busnumber
  554.                                                             SlotNumber.u.AsULONG,     // Slotnumber
  555.                                                             (PVOID) &(pci_config),    // Pointer for the PCI-Information
  556.                                                             sizeof(PCI_COMMON_CONFIG) );
  557.  
  558.                 if ((pci_config.VendorID    == PCICC32_VENDOR_ID) &&
  559.                         (pci_config.DeviceID    == PCICC32_DEVICE_ID) &&
  560.                         (pci_config.u.type0.SubSystemID == PCICC32_SUBSYS_ID) &&
  561.                         (pci_config.u.type0.SubVendorID == PCICC32_SUBVEN_ID) &&
  562.                         (pci_config.u.type0.BaseAddresses[3]))
  563.                 {
  564.                pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found];
  565.  
  566.                memcpy(&pciada->PCIDevice, &pci_config, sizeof(pci_config));
  567.                    pciada->Slot = SlotNumber;
  568.                    pciada->Bus  = j;
  569.  
  570.                    KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
  571.  
  572.                    (*found)++;
  573.                    if (*found >= PCICC32_MAX_PCIADA) return STATUS_SUCCESS;
  574.                 }
  575.           }
  576.         }              
  577.   }
  578.  
  579.   return STATUS_SUCCESS;
  580. }
  581.  
  582. //---------------------------------------------------------------
  583. // function to call for bug fix of PLX9050 build in bug
  584. //
  585. NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
  586. {
  587.         DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
  588.         int i;
  589.         ULONG dwData;
  590.         PCIADA *pciada;
  591.  
  592.         KdPrint(("PLX9050BugFix()\n"));
  593.  
  594.         for (i = 0; i < DeviceExtension->nPCIADAs; i++)
  595.         {
  596.                 pciada = &DeviceExtension->pciada[i];
  597.  
  598.                 if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[0]) & 0x80)
  599.                 {      
  600.                         KdPrint(("Changing address 0:0x%p with 4:0x%p\n",
  601.                                 pciada->PCIDevice.u.type0.BaseAddresses[0],
  602.                                 pciada->PCIDevice.u.type0.BaseAddresses[4]));
  603.  
  604.                         pciada->PCIDevice.u.type0.BaseAddresses[0] =           // exchange
  605.                                 pciada->PCIDevice.u.type0.BaseAddresses[4];
  606.                         pciada->PCIDevice.u.type0.BaseAddresses[4] = dwData;
  607.  
  608.                         if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  609.                                   pciada->Slot.u.AsULONG,
  610.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0],
  611.                                                 0x10, 4) != 4)
  612.                         return STATUS_UNSUCCESSFUL;
  613.  
  614.                         if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  615.                                   pciada->Slot.u.AsULONG,
  616.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[4],
  617.                                                 0x20, 4) != 4)
  618.                         return STATUS_UNSUCCESSFUL;
  619.                 }
  620.      
  621.                 if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[1]) & 0x80)
  622.                 {
  623.                         KdPrint(("Changing address 1:0x%p with 5:0x%p\n",
  624.                                 pciada->PCIDevice.u.type0.BaseAddresses[1],
  625.                                 pciada->PCIDevice.u.type0.BaseAddresses[5]));
  626.  
  627.                   pciada->PCIDevice.u.type0.BaseAddresses[1] =           // exchange
  628.                                 pciada->PCIDevice.u.type0.BaseAddresses[5];
  629.                   pciada->PCIDevice.u.type0.BaseAddresses[5] = dwData;
  630.  
  631.                   if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  632.                                   pciada->Slot.u.AsULONG,
  633.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1],
  634.                                                 0x14, 4) != 4)
  635.                         return STATUS_UNSUCCESSFUL;
  636.  
  637.                   if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  638.                                   pciada->Slot.u.AsULONG,
  639.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5],
  640.                                                 0x24, 4) != 4)
  641.                         return STATUS_UNSUCCESSFUL;
  642.                 }
  643.         }
  644.  
  645.         return STATUS_SUCCESS;
  646. }
  647.  
  648.  
  649. //------------------------------------------------------------------------
  650. //  reserve resources for PCIADAs
  651. //
  652. NTSTATUS PCICC32ExtractResources(PCIADA *pciada, PCM_RESOURCE_LIST pList)
  653. {
  654.         PCM_RESOURCE_LIST pResourceList;
  655.         PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
  656.         PCM_PARTIAL_RESOURCE_LIST pPartialList;
  657.         PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
  658.         int i;
  659.         int bug = 0;
  660.  
  661.         KdPrint(("PCICC32ExtractResources()\n"));
  662.  
  663.         pResourceList   = pList;
  664.         pFullDescriptor = pResourceList->List;
  665.         pPartialList    = &pFullDescriptor->PartialResourceList;
  666.  
  667.         for (i=0; i<(int)pPartialList->Count; i++)
  668.         {
  669.                 pPartialDescriptor = &pPartialList->PartialDescriptors[i];
  670.                 switch (pPartialDescriptor->Type)
  671.                 {
  672.                         case CmResourceTypeInterrupt:
  673.                                 pciada->Irql     = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
  674.                                 pciada->Vector   = pPartialDescriptor->u.Interrupt.Vector;
  675.                                 pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
  676.  
  677.                                 KdPrint(("Irq    : Irql: %d, Vector: %d, Affinity: %d\n",
  678.                                         pciada->Irql, pciada->Vector, pciada->Affinity));
  679.                                 break;
  680.                         case CmResourceTypeDma:
  681.                                 KdPrint(("Dma    : \n"));
  682.                                 break;
  683.                         case CmResourceTypePort:
  684.  
  685.                                 KdPrint(("Port   : 0x%p\n", pPartialDescriptor->u.Port.Start));
  686.                                 break;
  687.                         case CmResourceTypeMemory:
  688.                                 // special handling of PLXBUG here because of WIN2000
  689.                                 // WIN2000 doesn't recognize late address changes
  690.                                 if (!bug)
  691.                                 {
  692.                                         if (i == 0)
  693.                                         {
  694.                                                 pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  695.  
  696.                                                 if (pciada->pvPhysLcr.LowPart & 0x80)
  697.                                                         bug = 1;
  698.                                         }
  699.                                 }
  700.                                 else
  701.                                 {
  702.                                         if (i == 3)
  703.                                                 pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  704.                                 }
  705.  
  706.                                 if (i == 2)
  707.                                         pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
  708.  
  709.                                 KdPrint(("Memory : 0x%p\n", (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
  710.                                 break;
  711.                 }
  712.         }
  713.  
  714.         if (pciada->Irql == 0)
  715.                 return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
  716.  
  717.         KdPrint(("PCICC32ExtractResources() OK.\n"));
  718.  
  719.         return STATUS_SUCCESS;
  720. }
  721.  
  722. NTSTATUS PCICC32ReserveResources(PDEVICE_OBJECT device_Obj)
  723. {
  724.         PCM_RESOURCE_LIST pList = NULL;
  725.         NTSTATUS result = STATUS_SUCCESS;
  726.         int i;
  727.         DEVICE_EXT *pDevExt = (DEVICE_EXT*)(device_Obj->DeviceExtension);
  728.         int nPCIADAs = pDevExt->nPCIADAs;
  729.         PCIADA *pciada;
  730.     UNICODE_STRING DriverClassName;
  731.    
  732.         KdPrint(("PCICC32ReserveResources()\n"));
  733.  
  734.         // prepare resource claiming
  735.         RtlInitUnicodeString(&DriverClassName, L"PCICC32");
  736.  
  737.         // cycle through all busses and slots assigned to PCIADAs
  738.         for (i = 0; i < nPCIADAs; i++)
  739.     {
  740.                 pciada = &pDevExt->pciada[i];
  741.  
  742.                 result = HalAssignSlotResources(NULL, &DriverClassName, device_Obj->DriverObject, device_Obj,
  743.                         PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, &pList);
  744.  
  745.                 if (result != STATUS_SUCCESS)
  746.                         break;
  747.  
  748.                 result = PCICC32ExtractResources(pciada, pList);
  749.  
  750.                 if (result != STATUS_SUCCESS)
  751.                         break;
  752.         }
  753.  
  754.         // its my part to free allocated resources
  755.         ExFreePool(pList);
  756.  
  757.         KdPrint(("PCICC32ReserveResources(0x%08x)\n", result));
  758.  
  759.         return result;
  760. };
  761.  
  762. //------------------------------------------------------------------------
  763. //  free resources from PCIADAs
  764. //
  765. NTSTATUS PCICC32FreeResources(PDEVICE_OBJECT device_Obj)
  766. {
  767.         CM_RESOURCE_LIST ResList;
  768.         BOOLEAN          bConflict;
  769.     UNICODE_STRING   DriverClassName;
  770.  
  771.     KdPrint(("PCICC32FreeResources()\n"));
  772.  
  773.         RtlInitUnicodeString(&DriverClassName, L"PCICC32");
  774.  
  775.         ResList.Count = 0;
  776.  
  777.         IoReportResourceUsage(&DriverClassName, device_Obj->DriverObject,
  778.                                          &ResList, sizeof(ResList), device_Obj,
  779.                                                                          NULL, 0, FALSE, &bConflict);
  780.         return STATUS_SUCCESS;
  781. };
  782.  
  783.  
  784. //------------------------------------------------------------------------
  785. //  translate memory resources to neutral for PCIADAs
  786. //
  787. NTSTATUS PCICC32TranslateBusAddresses(PDEVICE_OBJECT device_Obj)
  788. {
  789.         int              i;
  790.         NTSTATUS         result = STATUS_SUCCESS;
  791.         int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
  792.         ULONG            memType0, memType2;
  793.         PCIADA           *pciada;
  794.  
  795.     KdPrint(("TranslateBusAddresseses()\n"));
  796.         for (i = 0; i < nPCIADAs; i++)
  797.         {
  798.       pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  799.  
  800.           memType0 = memType2 = 0;
  801.  
  802.           if (!(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysLcr, &memType0,
  803.                                                                &pciada->pvPhysLcr)) ||
  804.               !(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysIfr, &memType2,
  805.                                                                &pciada->pvPhysIfr)))
  806.           {
  807.                   result = STATUS_UNSUCCESSFUL;
  808.                   break;
  809.           }
  810.  
  811.           if ((memType0) || (memType2))
  812.           {
  813.                   result = STATUS_UNSUCCESSFUL;
  814.                   break;
  815.           }
  816.         }
  817.         return result;
  818. }
  819.  
  820. //------------------------------------------------------------------------
  821. //  map address spaces to virtual addresses
  822. //
  823. NTSTATUS PCICC32MapIOspaces(PDEVICE_OBJECT device_Obj)
  824. {
  825.         int              i;
  826.         DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
  827.         int                              nPCIADAs = pDevExt->nPCIADAs;
  828.         PCIADA           *pciada;
  829.  
  830.         KdPrint(("PCICC32MapIOspaces()\n"));
  831.  
  832.         for (i = 0; i < nPCIADAs; i++)
  833.         {
  834.        pciada = &pDevExt->pciada[i];
  835.  
  836.        if ((pciada->pvVirtLcr = MmMapIoSpace(pciada->pvPhysLcr, LCR_SPACE, FALSE)) == NULL)
  837.           return STATUS_UNSUCCESSFUL;
  838.        if ((pciada->pvVirtIfr = MmMapIoSpace(pciada->pvPhysIfr, IFR_SPACE, FALSE)) == NULL)
  839.           return STATUS_UNSUCCESSFUL;
  840.  
  841.            KdPrint(("PCIADA %d: LCR 0x%08x IFR 0x%08x\n", i, pciada->pvVirtLcr, pciada->pvVirtIfr));
  842.  
  843.            pciada->pwIntCSR = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x4C);
  844.            pciada->pwCntrl  = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x50);
  845.         }
  846.  
  847.         return STATUS_SUCCESS;
  848. }
  849.  
  850.  
  851. //------------------------------------------------------------------------
  852. //  initializes and registers a DPC routine for each pciada
  853. //
  854. NTSTATUS InitializeCustomDPCObjects(PDEVICE_OBJECT device_object)
  855. {
  856.         int              i;
  857.         DEVICE_EXT       *pDevExt = (DEVICE_EXT*)(device_object->DeviceExtension);
  858.         int              nPCIADAs = pDevExt->nPCIADAs;
  859.         PCIADA           *pciada;
  860.  
  861.         KdPrint(("InitializeCustomDPCObject()\n"));
  862.  
  863.         for (i = 0; i < nPCIADAs; i++)
  864.         {
  865.                 pciada = &pDevExt->pciada[i];
  866.                 KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
  867.         }
  868.  
  869.         return STATUS_SUCCESS;
  870. }
  871.  
  872. //------------------------------------------------------------------------
  873. // init structures a.s.o.
  874. //
  875. VOID PCICC32SoftInit(PDEVICE_OBJECT device_Obj)
  876. {
  877.         int i;
  878.         PCIADA *pciada;
  879.  
  880.         for (i = 0; i < PCICC32_MAX_PCIADA; i++)
  881.         {
  882.                 pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  883.  
  884.                 pciada->pvPhysLcr.QuadPart = pciada->pvPhysIfr.QuadPart = 0;
  885.                 pciada->pvVirtLcr = pciada->pvVirtIfr = NULL;
  886.  
  887.                 pciada->bConnected     = FALSE;   // connection still not verified
  888.                 pciada->wModuleNumber  = 0xFFFF;
  889.                 pciada->wFPGAVersion   = 0xFFFF;
  890.                 pciada->wModuleType    = 1;       // always CC32
  891.  
  892.                 pciada->InterruptObject = NULL;
  893.                 pciada->Irql                    = 0;
  894.                 pciada->Vector          = 0;
  895.                 pciada->Affinity                = 0;
  896.  
  897.                 pciada->dwLinkCount     = 0;
  898.  
  899.                 pciada->dwIrqStatus     = 0;
  900.                 pciada->pBlockingIrp    = (PIRP *)NULL;
  901.  
  902.                 pciada->pIrqControlFile = (FILE_OBJ *)NULL;
  903.         }
  904.  
  905.         // no CC32 associated to any PCIADA
  906.         for (i = 0; i < PCICC32_MAX_CC32; i++)
  907.           ((DEVICE_EXT*)(device_Obj->DeviceExtension))->cc32[i] = NULL;
  908. }
  909.  
  910. //------------------------------------------------------------------------
  911. // the ultimate starting point of a driver
  912. NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
  913. {
  914.         int            i;
  915.         PDEVICE_OBJECT device_object;                   // pointer to the device object
  916.         UNICODE_STRING device_name;
  917.         UNICODE_STRING symbol_name;
  918.         NTSTATUS result = STATUS_SUCCESS;
  919.         PCIADA         *pciada;                                 // pointer to a PCIADA
  920.         int            nPCIADAs;                                // count of PCIADAs
  921.         DEVICE_EXT     *DeviceExtension = NULL;
  922.  
  923.     KdPrint(("DriverEntry() ----%d.%d-------------------------\n", (DRIVER_VERSION >> 16) & 0xFFFF, DRIVER_VERSION & 0xFFFF));
  924.  
  925.         driverObj->DriverUnload = PCICC32Unload;
  926.         driverObj->MajorFunction[IRP_MJ_CREATE]            = PCICC32Open;
  927.         driverObj->MajorFunction[IRP_MJ_CLOSE]             = PCICC32Close;
  928.         driverObj->MajorFunction[IRP_MJ_READ]              = PCICC32Read;
  929.     driverObj->MajorFunction[IRP_MJ_WRITE]             = PCICC32Write;
  930.         driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]    = PCICC32DeviceControl;
  931.     driverObj->MajorFunction[IRP_MJ_SHUTDOWN]          = PCICC32Shutdown;
  932.  
  933.         RtlInitUnicodeString(&device_name, L"\\Device\\CC32");
  934.  
  935.         /* DeviceObject durch IO-Manager erzeugen */
  936.         result = IoCreateDevice( driverObj,           // DriverObject received by the DriverEntry Call
  937.                                                          sizeof(DEVICE_EXT),  // required Memory for the DeviceExtension
  938.                                                          &device_name,        // Name of the device in the device-Directory
  939.                                                          FILE_DEVICE_UNKNOWN, // Device-ID              
  940.                                                          0,                   // Device-Characteristics normal 0
  941.                                                          FALSE,               // TRUE : one Thread can open the driver
  942.                                                          &device_object);     // DeviceObject returned from the IO-Manager
  943.  
  944.         // defines how the data are handled between user / kernel Adress-Space  
  945.         device_object->Flags |= DO_DIRECT_IO;
  946.  
  947.         // anounce driver as symbolic device ---------------------------------
  948.         if (result == STATUS_SUCCESS)
  949.         {
  950.                 /* now the symbolic Link is created. If there is no S.L. a program cannot connect to the driver */
  951.                 RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
  952.                 result = IoCreateSymbolicLink(&symbol_name,&device_name);
  953.                 if (result != STATUS_SUCCESS)
  954.                 {
  955.                         IoDeleteDevice(device_object);
  956.                         return result;
  957.                 }
  958.         }
  959.         else
  960.                 return result;
  961.  
  962.         DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
  963.  
  964.         DeviceExtension->actualIrp  = NULL;
  965.         DeviceExtension->nInitState = 0;
  966.  
  967.         // init pciada structures ------------------------------------
  968.         PCICC32SoftInit(device_object);
  969.  
  970.         // search for PCIADAs ----------------------------------------
  971.         result   = SearchDevices(device_object);
  972.         nPCIADAs = DeviceExtension->nPCIADAs;
  973.  
  974.         if ((result != STATUS_SUCCESS) || !(nPCIADAs))
  975.         {
  976.                 PCICC32Unload(driverObj);    
  977.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  978.         }
  979.  
  980.         // request exclusive ownership of .. ---------------------------------
  981.         if ((result = PCICC32ReserveResources(device_object)) != STATUS_SUCCESS)
  982.         {
  983.                 PCICC32Unload(driverObj);    
  984.                 return result;
  985.         }
  986.         else
  987.                 DeviceExtension->nInitState++;
  988.  
  989.         // fix PLX9050 Bug -------------------------------------------
  990.         if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
  991.         {
  992.                 PCICC32Unload(driverObj);    
  993.                 return result;
  994.         }
  995.  
  996.         // translate BUS relative addresses ----------------------------------
  997.         if ((result = PCICC32TranslateBusAddresses(device_object)) != STATUS_SUCCESS)
  998.         {
  999.                 PCICC32Unload(driverObj);    
  1000.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1001.         }
  1002.         else
  1003.                 DeviceExtension->nInitState++;
  1004.  
  1005.         // translate Interrupt Resources used --------------------------------
  1006.         if ((result = PCICC32TranslateInterrupt(device_object)) != STATUS_SUCCESS)
  1007.         {
  1008.                 PCICC32Unload(driverObj);    
  1009.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1010.         }
  1011.         else
  1012.                 DeviceExtension->nInitState++;
  1013.        
  1014.         // map address spaces to virtual addresses ---------------------------
  1015.         if ((result = PCICC32MapIOspaces(device_object)) != STATUS_SUCCESS)
  1016.         {
  1017.                 PCICC32Unload(driverObj);    
  1018.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1019.         }
  1020.         else
  1021.                 DeviceExtension->nInitState++;
  1022.  
  1023.         // initialze my custom DPC objects -----------------------------------
  1024.         if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
  1025.         {
  1026.                 PCICC32Unload(driverObj);    
  1027.                 return result;
  1028.         }
  1029.         else
  1030.                 DeviceExtension->nInitState++;
  1031.  
  1032.         // disable all interrupts --------------------------------------------
  1033.         for (i = 0; i < nPCIADAs; i++)
  1034.         {
  1035.                 pciada = &DeviceExtension->pciada[i];
  1036.  
  1037.                 globalInterruptDisable(pciada);
  1038.         }
  1039.  
  1040.         // connect interrupts to service routines ----------------------------
  1041.         if ((result = PCICC32ConnectInterrupt(device_object)) != STATUS_SUCCESS)
  1042.         {
  1043.                 PCICC32Unload(driverObj);    
  1044.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1045.         }
  1046.         else
  1047.                 DeviceExtension->nInitState++;
  1048.  
  1049.         // scan all connected CC32 for info and later use -------------------
  1050.         if ((result = PCICC32ScanCC32(device_object)) != STATUS_SUCCESS)
  1051.         {
  1052.                 PCICC32Unload(driverObj);    
  1053.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1054.         }
  1055.  
  1056.         device_object->Flags &= ~DO_DEVICE_INITIALIZING;
  1057.  
  1058.     KdPrint(("DriverEntry() OK.\n"));
  1059.  
  1060.         return result;
  1061. }
  1062.  
  1063.