Subversion Repositories f9daq

Rev

Go to most recent revision | 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  = (USHORT) 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.         UNREFERENCED_PARAMETER(irp);
  313.         KdPrint(("PCICC32Shutdown()\n"));
  314.  
  315.         // deinit interfaces and interrupts
  316.         PCICC32DeInitPCIADAs(deviceObj);
  317.  
  318.     KdPrint(("PCICC32Shutdown() OK\n"));
  319.  
  320.         return STATUS_SUCCESS;
  321. }
  322.  
  323. //------------------------------------------------------------------------
  324. // called at ioctl()
  325. NTSTATUS PCICC32DeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
  326. {
  327.         PIO_STACK_LOCATION IrpStack;
  328.         int   nIndex;
  329.  
  330.         IrpStack  = IoGetCurrentIrpStackLocation(Irp);
  331.         nIndex    = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
  332.  
  333.     KdPrint(("PCICC32DeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
  334.  
  335.         if (nIndex > CTL_INDEX(PCICC32_LAST_CTL_CODE))
  336.         {
  337.                 KdPrint(("LastIndex(%d)\n", CTL_INDEX(PCICC32_LAST_CTL_CODE)));
  338.                 Irp->IoStatus.Status      = STATUS_UNSUCCESSFUL;
  339.                 Irp->IoStatus.Information = 0;
  340.                 IoCompleteRequest(Irp,IO_NO_INCREMENT);
  341.  
  342.         KdPrint(("PCICC32DeviceControl() FAIL.\n"));
  343.  
  344.                 return STATUS_UNSUCCESSFUL;
  345.         }
  346.  
  347.         return ioctl[nIndex](deviceObj, Irp, IrpStack);
  348. }
  349.  
  350.  
  351. //------------------------------------------------------------------------
  352. // called at read()
  353. static BOOLEAN PCICC32Read_kernel(PVOID pvContext)
  354. {
  355.         register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
  356.         register ULONG i = 0;
  357.         USHORT   wCntrl;
  358.  
  359.         wCntrl = READ_REGISTER_USHORT(context->pciada->pwCntrl);
  360.         if (context->file_obj->wBlockTransfer & AUTOREAD)
  361.         {
  362.                 wCntrl &= ~0x0004;  // enable autoread - set bit to 0
  363.                 WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);                               
  364.         }
  365.  
  366.         // do the read ---
  367.         if (context->file_obj->wBlockTransfer & UNTIL_NOT_Q)
  368.         {
  369.                 // read first time to get Q information
  370.                 register ULONG tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address);
  371.  
  372.                 if (context->file_obj->wAccessType == WORD_ACCESS)
  373.                 {
  374.                         PUSHORT pwBuffer = (PUSHORT)context->pOutputBuffer;
  375.                         PUSHORT pwBufEnd = (PUSHORT)((PUCHAR)context->pOutputBuffer + context->Length);
  376.  
  377.                         while ((tempBuffer & 0x80000000) && (pwBuffer < pwBufEnd))
  378.                         {
  379.                                 *pwBuffer++ = (USHORT)tempBuffer;
  380.                                 tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address);  // read the same address multiple times as long to get Q
  381.                                 i++;
  382.                         }
  383.                 }
  384.                 else
  385.                 {
  386.                         // LONG_ACCESS
  387.                         PULONG pdwBuffer = (PULONG)context->pOutputBuffer;
  388.                         PULONG pdwBufEnd = (PULONG)((PUCHAR)context->pOutputBuffer + context->Length);
  389.  
  390.                         while ((tempBuffer & 0x80000000) && (pdwBuffer < pdwBufEnd))
  391.                         {
  392.                                 *pdwBuffer++ = tempBuffer;
  393.                                 tempBuffer   = READ_REGISTER_ULONG((ULONG *)context->Address);  // read the same address multiple times as long to get Q
  394.                                 i++;
  395.                         }
  396.                 }
  397.  
  398.                 i *= context->file_obj->wAccessType;
  399.  
  400.                 KdPrint(("UNTIL_NOT_Q, 0x%08x bytes read\n", i));
  401.         }
  402.         else // no UNTIL_NOT_Q
  403.         {
  404.                 while (i < context->Length)
  405.                 {
  406.                         context->file_obj->fRead((void *)((PUCHAR)context->pOutputBuffer + i), (void *)context->Address);  // read the same address multiple times
  407.                         i += context->file_obj->wAccessType;
  408.                 }
  409.         }
  410.  
  411.         // disable autoread unconditionally - set bit to 1
  412.         wCntrl |= 0x0004;  
  413.         WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);
  414.  
  415.     context->Length = i;       
  416.  
  417.         return TRUE;
  418. }
  419.  
  420. NTSTATUS PCICC32Read(PDEVICE_OBJECT device_Obj, PIRP Irp)
  421. {
  422.         NTSTATUS        Status        = STATUS_SUCCESS;
  423.         PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  424.         DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  425.         SYNC_CONTEXT context;
  426.    
  427.         context.file_obj              = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  428.         context.pciada                = pDevExt->cc32[context.file_obj->uwAssociatedCC32];
  429.         context.pOutputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
  430.         context.Address           = IrpStack->Parameters.Read.ByteOffset.LowPart;  
  431.         context.Length            = 0;
  432.  
  433.         KdPrint(("PCICC32Read(%d)\n", context.file_obj->uwAssociatedCC32));
  434.  
  435.         if (context.Address > IFR_SPACE)
  436.                 Status = STATUS_ACCESS_VIOLATION;
  437.         else
  438.         {
  439.                 // do here in between what has to be done -----------------
  440.                 context.Length = IrpStack->Parameters.Read.Length;
  441.                 KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
  442.                 context.Address = (ULONG)context.pciada->pvVirtIfr + context.Address;
  443.  
  444.                 KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Read_kernel, &context);
  445.                 // do here in between what has to be done end -------------
  446.         }
  447.  
  448.         Irp->IoStatus.Status      = Status;  
  449.         Irp->IoStatus.Information = context.Length;  
  450.         IoCompleteRequest(Irp,IO_NO_INCREMENT);  
  451.  
  452.     KdPrint(("PCICC32Read(), Status = 0x%08x\n", Status));
  453.  
  454.         return Status;
  455. }
  456.  
  457.  
  458. //------------------------------------------------------------------------
  459. // called at write()
  460. static BOOLEAN PCICC32Write_kernel(PVOID pvContext)
  461. {
  462.         register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
  463.         register ULONG i = 0;
  464.  
  465.         // do the write ---
  466.         while (i < context->Length)
  467.         {
  468.                 context->file_obj->fWrite((void *)context->Address, (void *)((PUCHAR)context->pInputBuffer + i));  // write the same address multiple times
  469.                 i += context->file_obj->wAccessType;
  470.         }
  471.  
  472.         context->Length = i;
  473.  
  474.         return TRUE;
  475. }
  476.  
  477. NTSTATUS PCICC32Write(PDEVICE_OBJECT device_Obj, PIRP Irp)
  478. {
  479.         NTSTATUS        Status        = STATUS_SUCCESS;
  480.         PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  481.         DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  482.         SYNC_CONTEXT context;
  483.    
  484.         context.file_obj              = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  485.         context.pciada                = pDevExt->cc32[context.file_obj->uwAssociatedCC32];
  486.         context.pInputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
  487.         context.Address           = IrpStack->Parameters.Read.ByteOffset.LowPart;  
  488.         context.Length            = 0;
  489.  
  490.         KdPrint(("PCICC32Write(%d)\n", context.file_obj->uwAssociatedCC32));
  491.  
  492.         if (context.Address > IFR_SPACE)
  493.                 Status = STATUS_ACCESS_VIOLATION;
  494.         else
  495.         {
  496. //              register ULONG i = 0;
  497.  
  498.                 // do here in between what has to be done -----------------
  499.                 context.Length    = IrpStack->Parameters.Read.Length;
  500.                 KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
  501.                 context.Address   = (ULONG)context.pciada->pvVirtIfr + context.Address;
  502.  
  503.                 KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Write_kernel, &context);
  504.                 // do here in between what has to be done end -------------
  505.         }
  506.  
  507.  
  508.         Irp->IoStatus.Status      = Status;  
  509.         Irp->IoStatus.Information = context.Length;  
  510.         IoCompleteRequest(Irp,IO_NO_INCREMENT);  
  511.  
  512.     KdPrint(("PCICC32Write(), Status = 0x%08x\n", Status));
  513.  
  514.         return Status;
  515. }
  516.  
  517. //------------------------------------------------------------------------
  518. // search for pciada's
  519. //
  520. NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
  521. {
  522.   PCI_SLOT_NUMBER   SlotNumber;
  523.   PCI_COMMON_CONFIG pci_config;
  524.   PCIADA            *pciada;
  525.   ULONG             length;
  526.   int               *found;
  527.   int               i,j,k;
  528.  
  529.   KdPrint(("SearchDevices()\n"));
  530.  
  531.   // prepare structures ----------------------------------------
  532.   found  = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
  533.   *found = 0;
  534.   for (i = 0; i < PCICC32_MAX_PCIADA; i++)
  535.   {
  536.         pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  537.  
  538.         pciada->Bus                = -1;
  539.     pciada->Slot.u.AsULONG     = 0xFFFFFFFF;
  540.   }
  541.  
  542.   // search for pciada's ---------------------------------------
  543.   SlotNumber.u.bits.Reserved = 0;
  544.  
  545.   for (j = 0; j < PCI_MAX_BUSES; j++)
  546.   {
  547.     for (i = 0; i < PCI_MAX_DEVICES; i++)
  548.         {
  549.           SlotNumber.u.bits.DeviceNumber = i;
  550.           for (k = 0; k < PCI_MAX_FUNCTION; k++)
  551.           {
  552.                 SlotNumber.u.bits.FunctionNumber = k;
  553.             length = HalGetBusData( PCIConfiguration,         // Bustype
  554.                                                             j,                                    // PCI-Busnumber
  555.                                                             SlotNumber.u.AsULONG,     // Slotnumber
  556.                                                             (PVOID) &(pci_config),    // Pointer for the PCI-Information
  557.                                                             sizeof(PCI_COMMON_CONFIG) );
  558.  
  559.                 if ((pci_config.VendorID    == PCICC32_VENDOR_ID) &&
  560.                         (pci_config.DeviceID    == PCICC32_DEVICE_ID) &&
  561.                         (pci_config.u.type0.SubSystemID == PCICC32_SUBSYS_ID) &&
  562.                         (pci_config.u.type0.SubVendorID == PCICC32_SUBVEN_ID) &&
  563.                         (pci_config.u.type0.BaseAddresses[3]))
  564.                 {
  565.                pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found];
  566.  
  567.                memcpy(&pciada->PCIDevice, &pci_config, sizeof(pci_config));
  568.                    pciada->Slot = SlotNumber;
  569.                    pciada->Bus  = j;
  570.  
  571.                    KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
  572.  
  573.                    (*found)++;
  574.                    if (*found >= PCICC32_MAX_PCIADA) return STATUS_SUCCESS;
  575.                 }
  576.           }
  577.         }              
  578.   }
  579.  
  580.   return STATUS_SUCCESS;
  581. }
  582.  
  583. //---------------------------------------------------------------
  584. // function to call for bug fix of PLX9050 build in bug
  585. //
  586. NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
  587. {
  588.         DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
  589.         int i;
  590.         ULONG dwData;
  591.         PCIADA *pciada;
  592.  
  593.         KdPrint(("PLX9050BugFix()\n"));
  594.  
  595.         for (i = 0; i < DeviceExtension->nPCIADAs; i++)
  596.         {
  597.                 pciada = &DeviceExtension->pciada[i];
  598.  
  599.                 if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[0]) & 0x80)
  600.                 {      
  601.                         KdPrint(("Changing address 0:0x%p with 4:0x%p\n",
  602.                                 pciada->PCIDevice.u.type0.BaseAddresses[0],
  603.                                 pciada->PCIDevice.u.type0.BaseAddresses[4]));
  604.  
  605.                         pciada->PCIDevice.u.type0.BaseAddresses[0] =           // exchange
  606.                                 pciada->PCIDevice.u.type0.BaseAddresses[4];
  607.                         pciada->PCIDevice.u.type0.BaseAddresses[4] = dwData;
  608.  
  609.                         if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  610.                                   pciada->Slot.u.AsULONG,
  611.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0],
  612.                                                 0x10, 4) != 4)
  613.                         return STATUS_UNSUCCESSFUL;
  614.  
  615.                         if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  616.                                   pciada->Slot.u.AsULONG,
  617.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[4],
  618.                                                 0x20, 4) != 4)
  619.                         return STATUS_UNSUCCESSFUL;
  620.                 }
  621.      
  622.                 if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[1]) & 0x80)
  623.                 {
  624.                         KdPrint(("Changing address 1:0x%p with 5:0x%p\n",
  625.                                 pciada->PCIDevice.u.type0.BaseAddresses[1],
  626.                                 pciada->PCIDevice.u.type0.BaseAddresses[5]));
  627.  
  628.                   pciada->PCIDevice.u.type0.BaseAddresses[1] =           // exchange
  629.                                 pciada->PCIDevice.u.type0.BaseAddresses[5];
  630.                   pciada->PCIDevice.u.type0.BaseAddresses[5] = dwData;
  631.  
  632.                   if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  633.                                   pciada->Slot.u.AsULONG,
  634.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1],
  635.                                                 0x14, 4) != 4)
  636.                         return STATUS_UNSUCCESSFUL;
  637.  
  638.                   if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
  639.                                   pciada->Slot.u.AsULONG,
  640.                                         (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5],
  641.                                                 0x24, 4) != 4)
  642.                         return STATUS_UNSUCCESSFUL;
  643.                 }
  644.         }
  645.  
  646.         return STATUS_SUCCESS;
  647. }
  648.  
  649.  
  650. //------------------------------------------------------------------------
  651. //  reserve resources for PCIADAs
  652. //
  653. NTSTATUS PCICC32ExtractResources(PCIADA *pciada, PCM_RESOURCE_LIST pList)
  654. {
  655.         PCM_RESOURCE_LIST pResourceList;
  656.         PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
  657.         PCM_PARTIAL_RESOURCE_LIST pPartialList;
  658.         PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
  659.         int i;
  660.         int bug = 0;
  661.  
  662.         KdPrint(("PCICC32ExtractResources()\n"));
  663.  
  664.         pResourceList   = pList;
  665.         pFullDescriptor = pResourceList->List;
  666.         pPartialList    = &pFullDescriptor->PartialResourceList;
  667.  
  668.         for (i=0; i<(int)pPartialList->Count; i++)
  669.         {
  670.                 pPartialDescriptor = &pPartialList->PartialDescriptors[i];
  671.                 switch (pPartialDescriptor->Type)
  672.                 {
  673.                         case CmResourceTypeInterrupt:
  674.                                 pciada->Irql     = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
  675.                                 pciada->Vector   = pPartialDescriptor->u.Interrupt.Vector;
  676.                                 pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
  677.  
  678.                                 KdPrint(("Irq    : Irql: %d, Vector: %d, Affinity: %d\n",
  679.                                         pciada->Irql, pciada->Vector, pciada->Affinity));
  680.                                 break;
  681.                         case CmResourceTypeDma:
  682.                                 KdPrint(("Dma    : \n"));
  683.                                 break;
  684.                         case CmResourceTypePort:
  685.  
  686.                                 KdPrint(("Port   : 0x%p\n", pPartialDescriptor->u.Port.Start));
  687.                                 break;
  688.                         case CmResourceTypeMemory:
  689.                                 // special handling of PLXBUG here because of WIN2000
  690.                                 // WIN2000 doesn't recognize late address changes
  691.                                 if (!bug)
  692.                                 {
  693.                                         if (i == 0)
  694.                                         {
  695.                                                 pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  696.  
  697.                                                 if (pciada->pvPhysLcr.LowPart & 0x80)
  698.                                                         bug = 1;
  699.                                         }
  700.                                 }
  701.                                 else
  702.                                 {
  703.                                         if (i == 3)
  704.                                                 pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  705.                                 }
  706.  
  707.                                 if (i == 2)
  708.                                         pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
  709.  
  710.                                 KdPrint(("Memory : 0x%p\n", (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
  711.                                 break;
  712.                 }
  713.         }
  714.  
  715.         if (pciada->Irql == 0)
  716.                 return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
  717.  
  718.         KdPrint(("PCICC32ExtractResources() OK.\n"));
  719.  
  720.         return STATUS_SUCCESS;
  721. }
  722.  
  723. NTSTATUS PCICC32ReserveResources(PDEVICE_OBJECT device_Obj)
  724. {
  725.         PCM_RESOURCE_LIST pList = NULL;
  726.         NTSTATUS result = STATUS_SUCCESS;
  727.         int i;
  728.         DEVICE_EXT *pDevExt = (DEVICE_EXT*)(device_Obj->DeviceExtension);
  729.         int nPCIADAs = pDevExt->nPCIADAs;
  730.         PCIADA *pciada;
  731.     UNICODE_STRING DriverClassName;
  732.    
  733.         KdPrint(("PCICC32ReserveResources()\n"));
  734.  
  735.         // prepare resource claiming
  736.         RtlInitUnicodeString(&DriverClassName, L"PCICC32");
  737.  
  738.         // cycle through all busses and slots assigned to PCIADAs
  739.         for (i = 0; i < nPCIADAs; i++)
  740.     {
  741.                 pciada = &pDevExt->pciada[i];
  742.  
  743.                 result = HalAssignSlotResources(NULL, &DriverClassName, device_Obj->DriverObject, device_Obj,
  744.                         PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, &pList);
  745.  
  746.                 if (result != STATUS_SUCCESS)
  747.                         break;
  748.  
  749.                 result = PCICC32ExtractResources(pciada, pList);
  750.  
  751.                 if (result != STATUS_SUCCESS)
  752.                         break;
  753.         }
  754.  
  755.         // its my part to free allocated resources
  756.         ExFreePool(pList);
  757.  
  758.         KdPrint(("PCICC32ReserveResources(0x%08x)\n", result));
  759.  
  760.         return result;
  761. };
  762.  
  763. //------------------------------------------------------------------------
  764. //  free resources from PCIADAs
  765. //
  766. NTSTATUS PCICC32FreeResources(PDEVICE_OBJECT device_Obj)
  767. {
  768.         CM_RESOURCE_LIST ResList;
  769.         BOOLEAN          bConflict;
  770.     UNICODE_STRING   DriverClassName;
  771.  
  772.     KdPrint(("PCICC32FreeResources()\n"));
  773.  
  774.         RtlInitUnicodeString(&DriverClassName, L"PCICC32");
  775.  
  776.         ResList.Count = 0;
  777.  
  778.         IoReportResourceUsage(&DriverClassName, device_Obj->DriverObject,
  779.                                          &ResList, sizeof(ResList), device_Obj,
  780.                                                                          NULL, 0, FALSE, &bConflict);
  781.         return STATUS_SUCCESS;
  782. };
  783.  
  784.  
  785. //------------------------------------------------------------------------
  786. //  translate memory resources to neutral for PCIADAs
  787. //
  788. NTSTATUS PCICC32TranslateBusAddresses(PDEVICE_OBJECT device_Obj)
  789. {
  790.         int              i;
  791.         NTSTATUS         result = STATUS_SUCCESS;
  792.         int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
  793.         ULONG            memType0, memType2;
  794.         PCIADA           *pciada;
  795.  
  796.     KdPrint(("TranslateBusAddresseses()\n"));
  797.         for (i = 0; i < nPCIADAs; i++)
  798.         {
  799.       pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  800.  
  801.           memType0 = memType2 = 0;
  802.  
  803.           if (!(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysLcr, &memType0,
  804.                                                                &pciada->pvPhysLcr)) ||
  805.               !(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysIfr, &memType2,
  806.                                                                &pciada->pvPhysIfr)))
  807.           {
  808.                   result = STATUS_UNSUCCESSFUL;
  809.                   break;
  810.           }
  811.  
  812.           if ((memType0) || (memType2))
  813.           {
  814.                   result = STATUS_UNSUCCESSFUL;
  815.                   break;
  816.           }
  817.         }
  818.         return result;
  819. }
  820.  
  821. //------------------------------------------------------------------------
  822. //  map address spaces to virtual addresses
  823. //
  824. NTSTATUS PCICC32MapIOspaces(PDEVICE_OBJECT device_Obj)
  825. {
  826.         int              i;
  827.         DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
  828.         int                              nPCIADAs = pDevExt->nPCIADAs;
  829.         PCIADA           *pciada;
  830.  
  831.         KdPrint(("PCICC32MapIOspaces()\n"));
  832.  
  833.         for (i = 0; i < nPCIADAs; i++)
  834.         {
  835.        pciada = &pDevExt->pciada[i];
  836.  
  837.        if ((pciada->pvVirtLcr = MmMapIoSpace(pciada->pvPhysLcr, LCR_SPACE, FALSE)) == NULL)
  838.           return STATUS_UNSUCCESSFUL;
  839.        if ((pciada->pvVirtIfr = MmMapIoSpace(pciada->pvPhysIfr, IFR_SPACE, FALSE)) == NULL)
  840.           return STATUS_UNSUCCESSFUL;
  841.  
  842.            KdPrint(("PCIADA %d: LCR 0x%08x IFR 0x%08x\n", i, pciada->pvVirtLcr, pciada->pvVirtIfr));
  843.  
  844.            pciada->pwIntCSR = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x4C);
  845.            pciada->pwCntrl  = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x50);
  846.         }
  847.  
  848.         return STATUS_SUCCESS;
  849. }
  850.  
  851.  
  852. //------------------------------------------------------------------------
  853. //  initializes and registers a DPC routine for each pciada
  854. //
  855. NTSTATUS InitializeCustomDPCObjects(PDEVICE_OBJECT device_object)
  856. {
  857.         int              i;
  858.         DEVICE_EXT       *pDevExt = (DEVICE_EXT*)(device_object->DeviceExtension);
  859.         int              nPCIADAs = pDevExt->nPCIADAs;
  860.         PCIADA           *pciada;
  861.  
  862.         KdPrint(("InitializeCustomDPCObject()\n"));
  863.  
  864.         for (i = 0; i < nPCIADAs; i++)
  865.         {
  866.                 pciada = &pDevExt->pciada[i];
  867.                 KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
  868.         }
  869.  
  870.         return STATUS_SUCCESS;
  871. }
  872.  
  873. //------------------------------------------------------------------------
  874. // init structures a.s.o.
  875. //
  876. VOID PCICC32SoftInit(PDEVICE_OBJECT device_Obj)
  877. {
  878.         int i;
  879.         PCIADA *pciada;
  880.  
  881.         for (i = 0; i < PCICC32_MAX_PCIADA; i++)
  882.         {
  883.                 pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  884.  
  885.                 pciada->pvPhysLcr.QuadPart = pciada->pvPhysIfr.QuadPart = 0;
  886.                 pciada->pvVirtLcr = pciada->pvVirtIfr = NULL;
  887.  
  888.                 pciada->bConnected     = FALSE;   // connection still not verified
  889.                 pciada->wModuleNumber  = 0xFFFF;
  890.                 pciada->wFPGAVersion   = 0xFFFF;
  891.                 pciada->wModuleType    = 1;       // always CC32
  892.  
  893.                 pciada->InterruptObject = NULL;
  894.                 pciada->Irql                    = 0;
  895.                 pciada->Vector          = 0;
  896.                 pciada->Affinity                = 0;
  897.  
  898.                 pciada->dwLinkCount     = 0;
  899.  
  900.                 pciada->dwIrqStatus     = 0;
  901.                 pciada->pBlockingIrp    = (PIRP *)NULL;
  902.  
  903.                 pciada->pIrqControlFile = (FILE_OBJ *)NULL;
  904.         }
  905.  
  906.         // no CC32 associated to any PCIADA
  907.         for (i = 0; i < PCICC32_MAX_CC32; i++)
  908.           ((DEVICE_EXT*)(device_Obj->DeviceExtension))->cc32[i] = NULL;
  909. }
  910.  
  911. //------------------------------------------------------------------------
  912. // the ultimate starting point of a driver
  913. NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
  914. {
  915.         int            i;
  916.         PDEVICE_OBJECT device_object;                   // pointer to the device object
  917.         UNICODE_STRING device_name;
  918.         UNICODE_STRING symbol_name;
  919.         NTSTATUS result = STATUS_SUCCESS;
  920.         PCIADA         *pciada;                                 // pointer to a PCIADA
  921.         int            nPCIADAs;                                // count of PCIADAs
  922.         DEVICE_EXT     *DeviceExtension = NULL;
  923.         UNREFERENCED_PARAMETER(regPath);
  924.     KdPrint(("DriverEntry() ----%d.%d-------------------------\n", (DRIVER_VERSION >> 16) & 0xFFFF, DRIVER_VERSION & 0xFFFF));
  925.  
  926.         driverObj->DriverUnload = PCICC32Unload;
  927.         driverObj->MajorFunction[IRP_MJ_CREATE]            = PCICC32Open;
  928.         driverObj->MajorFunction[IRP_MJ_CLOSE]             = PCICC32Close;
  929.         driverObj->MajorFunction[IRP_MJ_READ]              = PCICC32Read;
  930.     driverObj->MajorFunction[IRP_MJ_WRITE]             = PCICC32Write;
  931.         driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]    = PCICC32DeviceControl;
  932.     driverObj->MajorFunction[IRP_MJ_SHUTDOWN]          = PCICC32Shutdown;
  933.  
  934.         RtlInitUnicodeString(&device_name, L"\\Device\\CC32");
  935.  
  936.         /* DeviceObject durch IO-Manager erzeugen */
  937.         result = IoCreateDevice( driverObj,           // DriverObject received by the DriverEntry Call
  938.                                                          sizeof(DEVICE_EXT),  // required Memory for the DeviceExtension
  939.                                                          &device_name,        // Name of the device in the device-Directory
  940.                                                          FILE_DEVICE_UNKNOWN, // Device-ID              
  941.                                                          0,                   // Device-Characteristics normal 0
  942.                                                          FALSE,               // TRUE : one Thread can open the driver
  943.                                                          &device_object);     // DeviceObject returned from the IO-Manager
  944.  
  945.         // defines how the data are handled between user / kernel Adress-Space  
  946.         device_object->Flags |= DO_DIRECT_IO;
  947.  
  948.         // anounce driver as symbolic device ---------------------------------
  949.         if (result == STATUS_SUCCESS)
  950.         {
  951.                 /* now the symbolic Link is created. If there is no S.L. a program cannot connect to the driver */
  952.                 RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
  953.                 result = IoCreateSymbolicLink(&symbol_name,&device_name);
  954.                 if (result != STATUS_SUCCESS)
  955.                 {
  956.                         IoDeleteDevice(device_object);
  957.                         return result;
  958.                 }
  959.         }
  960.         else
  961.                 return result;
  962.  
  963.         DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
  964.  
  965.         DeviceExtension->actualIrp  = NULL;
  966.         DeviceExtension->nInitState = 0;
  967.  
  968.         // init pciada structures ------------------------------------
  969.         PCICC32SoftInit(device_object);
  970.  
  971.         // search for PCIADAs ----------------------------------------
  972.         result   = SearchDevices(device_object);
  973.         nPCIADAs = DeviceExtension->nPCIADAs;
  974.  
  975.         if ((result != STATUS_SUCCESS) || !(nPCIADAs))
  976.         {
  977.                 PCICC32Unload(driverObj);    
  978.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  979.         }
  980.  
  981.         // request exclusive ownership of .. ---------------------------------
  982.         if ((result = PCICC32ReserveResources(device_object)) != STATUS_SUCCESS)
  983.         {
  984.                 PCICC32Unload(driverObj);    
  985.                 return result;
  986.         }
  987.         else
  988.                 DeviceExtension->nInitState++;
  989.  
  990.         // fix PLX9050 Bug -------------------------------------------
  991.         if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
  992.         {
  993.                 PCICC32Unload(driverObj);    
  994.                 return result;
  995.         }
  996.  
  997.         // translate BUS relative addresses ----------------------------------
  998.         if ((result = PCICC32TranslateBusAddresses(device_object)) != STATUS_SUCCESS)
  999.         {
  1000.                 PCICC32Unload(driverObj);    
  1001.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1002.         }
  1003.         else
  1004.                 DeviceExtension->nInitState++;
  1005.  
  1006.         // translate Interrupt Resources used --------------------------------
  1007.         if ((result = PCICC32TranslateInterrupt(device_object)) != STATUS_SUCCESS)
  1008.         {
  1009.                 PCICC32Unload(driverObj);    
  1010.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1011.         }
  1012.         else
  1013.                 DeviceExtension->nInitState++;
  1014.        
  1015.         // map address spaces to virtual addresses ---------------------------
  1016.         if ((result = PCICC32MapIOspaces(device_object)) != STATUS_SUCCESS)
  1017.         {
  1018.                 PCICC32Unload(driverObj);    
  1019.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1020.         }
  1021.         else
  1022.                 DeviceExtension->nInitState++;
  1023.  
  1024.         // initialze my custom DPC objects -----------------------------------
  1025.         if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
  1026.         {
  1027.                 PCICC32Unload(driverObj);    
  1028.                 return result;
  1029.         }
  1030.         else
  1031.                 DeviceExtension->nInitState++;
  1032.  
  1033.         // disable all interrupts --------------------------------------------
  1034.         for (i = 0; i < nPCIADAs; i++)
  1035.         {
  1036.                 pciada = &DeviceExtension->pciada[i];
  1037.  
  1038.                 globalInterruptDisable(pciada);
  1039.         }
  1040.  
  1041.         // connect interrupts to service routines ----------------------------
  1042.         if ((result = PCICC32ConnectInterrupt(device_object)) != STATUS_SUCCESS)
  1043.         {
  1044.                 PCICC32Unload(driverObj);    
  1045.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1046.         }
  1047.         else
  1048.                 DeviceExtension->nInitState++;
  1049.  
  1050.         // scan all connected CC32 for info and later use -------------------
  1051.         if ((result = PCICC32ScanCC32(device_object)) != STATUS_SUCCESS)
  1052.         {
  1053.                 PCICC32Unload(driverObj);    
  1054.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1055.         }
  1056.  
  1057.         device_object->Flags &= ~DO_DEVICE_INITIALIZING;
  1058.  
  1059.     KdPrint(("DriverEntry() OK.\n"));
  1060.  
  1061.         return result;
  1062. }
  1063.  
  1064.