Subversion Repositories f9daq

Rev

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

  1. //-------------------------------------------------------------------------
  2. // WINNT driver for PCIVME interface from ARW Elektronik, Germany ---------
  3. // the main body of the driver
  4. //
  5. // (c) 1999-2004 ARW Elektronik
  6. //
  7. // this source code is published under GPL (Open Source). You can use, redistrubute 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. // $Log: pcivme_drv.c,v $
  16. // Revision 1.3  2004/07/24 07:07:26  klaus
  17. // Update copyright to 2004
  18. //
  19. //
  20. // what                                            who          when
  21. // started                                         AR           15.06.1999
  22. // first release 1.0                               AR           17.10.1999
  23. // fixed error in PLX9050Bug                       AR           28.02.2000
  24. // PLX9050Bugfix bug fixed                         AR           03.03.2000
  25. // PCICC32 CAMAC Interface conflict solved         AR           03.03.2000
  26. // Version 1.1 released                            AR           03.03.2000
  27. // register all used resources, the idle too       AR           25.11.2001
  28. // changed resource allocation caused by WIN2000   AR           08.06.2002
  29. //
  30.  
  31. //-------------------------------------------------------------------------
  32. // INCLUDES
  33. //
  34. #include <initguid.h>
  35. #include <wdmguid.h>
  36. #include <ntddk.h>
  37. #include <devioctl.h>
  38. #include <pcivme_drv.h>
  39. #include <pcivme_v.h>
  40. #include <pcivme_io.h>
  41. #include <pcivme_i.h>
  42. #include <pcivme.h>
  43. #include <pciif.h>
  44. #include <pcivme_fifo.h>
  45. //------------------------------------------------------------------------
  46. // DEFINES
  47. //
  48. #define arraysize(p) (sizeof(p)/sizeof((p)[0]))
  49.  
  50. #ifndef DWORD
  51. #define DWORD ULONG
  52. #endif
  53.  
  54. #ifndef WORD
  55. #define WORD USHORT
  56. #endif
  57.  
  58. #define CTL_INDEX(x) ((x >> 2) & 0x7FF)  // get user control code as index
  59. #define IRQ_LIST_LENGTH 128     // max count of irqs in FIFO for each file_obj
  60.  
  61. #define RESOURCE_ENTRY_COUNT 6          // WIN2000 forces to claim all entries
  62.  
  63. #define DOS_DEVICE_NAME L"\\DosDevices\\PCIVME:"
  64.  
  65. //------------------------------------------------------------------------
  66. // GLOBALS
  67. //
  68.  
  69. //------------------------------------------------------------------------
  70. // FUNCTIONS
  71. //
  72.  
  73. //------------------------------------------------------------------------
  74. // exchange the pointer to Bus Error
  75. //
  76. PBOOLEAN ExchangePointer(PBOOLEAN *current, PBOOLEAN next)
  77. {
  78.         PBOOLEAN pb;
  79.  
  80.         pb       = *current;
  81.         *current = next;
  82.  
  83.         return pb;
  84. }
  85.  
  86. //------------------------------------------------------------------------
  87. // get the vmemm number out of the filename
  88. //
  89. NTSTATUS InterpreteFileName(PCHAR name, int *nVmemm)
  90. {
  91.         char *ptr = name;
  92.     char *n   = "vmemm";
  93.         int  h = -1;  // high part
  94.         int  l = -1;  // low part
  95.  
  96.         if (*ptr == '\\') ptr++; // jump over leading ...
  97.  
  98.     while (*n)                           // compare the basename
  99.           if (*n == tolower(*ptr))     
  100.           {
  101.                   n++;
  102.                   ptr++;
  103.           }
  104.           else
  105.                   return STATUS_NO_SUCH_FILE;
  106.  
  107.         h = *ptr - '0';                  // get the number
  108.         ptr++;
  109.         l = *ptr - '0';
  110.  
  111.         if (*ptr == 0)                   // still over the end ??
  112.         {
  113.                 l = h;
  114.                 h = 0;
  115.         }
  116.         else
  117.           ptr++;
  118.  
  119.         if ((h < 0) || (l < 0) || (*ptr != 0))  // anything wrong ??
  120.                   return STATUS_NO_SUCH_FILE;
  121.  
  122.         *nVmemm = (h * 10) + l;  // calculate number
  123.  
  124.         if (*nVmemm >= PCIVME_MAX_VMEMM) // out of range ??
  125.                   return STATUS_NO_SUCH_FILE;
  126.  
  127.         return STATUS_SUCCESS;
  128. }
  129.  
  130. //------------------------------------------------------------------------
  131. // the ultimate driver unload
  132. VOID PCIVMEUnload(PDRIVER_OBJECT driverObj)
  133. {
  134.         int              i;
  135.         UNICODE_STRING symbol_name;
  136.         if (!driverObj->DeviceObject) {
  137.                 KdPrint(("PCIVMEUnload() DeviceObject does not exist \n"));
  138.                 return;
  139.         }
  140.         DEVICE_EXT *ext = (DEVICE_EXT*)(driverObj->DeviceObject->DeviceExtension);
  141.         int         nPCIADAs = ext->nPCIADAs;
  142.         PCIADA      *pciada;
  143.  
  144.         KdPrint(("PCIVMEUnload() InitState %d \n", ext->nInitState ));
  145.  
  146.  
  147.         if (ext->nInitState!=100) return;
  148.  
  149.         switch (ext->nInitState)
  150.         {
  151.                 case 8:
  152.                 case 7:
  153.                         // stop interrupts and shut off
  154.                         PCIVMEDeInitPCIADAs(driverObj->DeviceObject);
  155.                         PCIVMEDisConnectInterrupt(driverObj->DeviceObject);
  156.  
  157.                         // remove interrupt lists
  158.                         for (i = 0; i < nPCIADAs; i++)
  159.                         {
  160.                                 pciada = &ext->pciada[i];
  161.  
  162.                                 // removeQueueFromList(...)
  163.                                 while (IsListEmpty(&pciada->IrqListList) == FALSE)
  164.                                 {
  165.                                         PLIST_ENTRY pList;
  166.                                         FIFO_LIST   *next;
  167.                                
  168.                                         KdPrint(("RemoveHeadList(0x%08x)\n", &pciada->IrqListList));
  169.                                         pList = RemoveHeadList(&pciada->IrqListList);
  170.                                         next  = CONTAINING_RECORD(pList, FIFO_LIST, entry);
  171.  
  172.                                         ExFreePool((PVOID)next);
  173.                                 }
  174.                         }
  175.                 case 6:
  176.                         // InitializeIRPQueue has no counterpart
  177.                 case 5:
  178.                         // KeInitializeDpc has no counterpart
  179.                 case 4:
  180.                         // release io spaces
  181.                         for (i = 0; i < nPCIADAs; i++)
  182.                         {
  183.                                 pciada = &ext->pciada[i];
  184.  
  185.                                 if (pciada->pvVirtLcr != NULL)
  186.                                         MmUnmapIoSpace(pciada->pvVirtLcr, LCR_SPACE);
  187.                                 if (pciada->pvVirtIfr != NULL)
  188.                                         MmUnmapIoSpace(pciada->pvVirtIfr, IFR_SPACE);
  189.                         }
  190.                 case 3:
  191.                         // HalGetInterruptVector has no counterpart
  192.                 case 2:
  193.                         // HalTranslateBusAddress has no counterpart
  194.                 case 1:
  195.                         // PCIVMEFreeResources(driverObj->DeviceObject); // not used in pnp
  196.                 default:
  197.                 case 0:
  198.                         RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
  199.  
  200.                         // delete the symbolicLink in the registry
  201.                         IoDeleteSymbolicLink( &symbol_name);
  202.  
  203.                         // delete the deviceObject
  204.  
  205.                         if (ext->LowerDeviceObject) IoDetachDevice(ext->LowerDeviceObject);
  206.                         IoDeleteDevice(driverObj->DeviceObject);
  207.         }
  208.        
  209.         KdPrint(("PCIVMEUnload() OK.\n"));
  210. }
  211.  
  212.  
  213. //------------------------------------------------------------------------
  214. // called at CreateFile()
  215. NTSTATUS PCIVMEOpen(PDEVICE_OBJECT deviceObj, PIRP Irp)
  216. {
  217.         NTSTATUS result = STATUS_SUCCESS;
  218.     ANSI_STRING name;
  219.     int nVmemm;
  220.         int i;
  221.         DEVICE_EXT      *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
  222.         PCIADA      *pciada;
  223.         FILE_OBJ        *file_obj = (FILE_OBJ *)NULL;
  224.  
  225.         name.Buffer = NULL;
  226.     name.MaximumLength = 80;
  227.  
  228.         result = RtlUnicodeStringToAnsiString(&name, &(Irp->Tail.Overlay.OriginalFileObject->FileName), TRUE);
  229.         if (result != STATUS_SUCCESS) goto fin;
  230.  
  231.         result = InterpreteFileName(name.Buffer, &nVmemm);
  232.     if (result != STATUS_SUCCESS) goto fin;
  233.  
  234.     KdPrint(("PCIVMEOpen(%d)\n", nVmemm));
  235.         RtlFreeAnsiString(&name);
  236.  
  237.     file_obj = (FILE_OBJ *)ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_OBJ),'nepo');
  238.         if (file_obj == (FILE_OBJ *)NULL)
  239.         {
  240.                 result = STATUS_NO_MEMORY;
  241.                 goto fin;
  242.         }
  243.  
  244.         file_obj->uwAssociatedVMEMM = (USHORT) nVmemm;
  245.         file_obj->bAddressModifier  = 0x39;
  246.         file_obj->bAccessType       = BYTE_ACCESS;
  247.         file_obj->bIncrement        = BYTE_ACCESS; // increments each byte
  248.         file_obj->dwAccessBase      = 0;           // normal setting for all but extended
  249.  
  250.         file_obj->bQueueIrq                     = FALSE;
  251.         result = InitializeFIFO(IRQ_LIST_LENGTH, &file_obj->pIrqListHandle);
  252.         if (result != STATUS_SUCCESS) goto fin;
  253.  
  254.     Irp->Tail.Overlay.OriginalFileObject->FsContext = (PVOID)file_obj;
  255.  
  256.         result = PCIVMEScanVMEMM(deviceObj);
  257.         if (result != STATUS_SUCCESS) goto fin;
  258.  
  259.         for (i = 0; i < pDevExt->nPCIADAs; i++)
  260.         {
  261.           pciada = &pDevExt->pciada[i];
  262.  
  263.           if (pciada->wModuleNumber == nVmemm)
  264.           {
  265.                   pDevExt->vmemm[nVmemm] = pciada; // create association
  266.                   pciada->dwLinkCount++;
  267.                   break;
  268.           }
  269.         }
  270.  
  271.         if (i >= pDevExt->nPCIADAs)
  272.         {
  273.                 result = STATUS_NO_SUCH_FILE;
  274.                 goto fin;
  275.         }
  276.  
  277.         fin:
  278.         Irp->IoStatus.Status = result;
  279.         Irp->IoStatus.Information = 0;
  280.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
  281.  
  282.         // be careful when releasing allocated memory !
  283.         if (result != STATUS_SUCCESS)
  284.                 if (file_obj != (FILE_OBJ *)NULL)
  285.                         if (file_obj->pIrqListHandle != (PVOID)NULL)
  286.                                 DestroyFIFO(file_obj->pIrqListHandle);
  287.  
  288.         return result;
  289. }
  290.  
  291. //------------------------------------------------------------------------
  292. // called at close()
  293. NTSTATUS PCIVMEClose(PDEVICE_OBJECT deviceObj, PIRP Irp)
  294. {
  295.         DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(deviceObj->DeviceExtension);
  296.         FILE_OBJ    *file_obj = (FILE_OBJ *)NULL;
  297.         PCIADA      *pciada;                   
  298.  
  299.         file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  300.  
  301.     KdPrint(("PCIVMEClose(%d)\n", file_obj->uwAssociatedVMEMM));
  302.  
  303.         if (file_obj != (FILE_OBJ *)NULL)
  304.         {
  305.                 pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
  306.                 pciada->dwLinkCount--;
  307.  
  308.                 // remove the ListEntry(s) associated with this path
  309.         removeQueueFromList(file_obj, pciada);
  310.  
  311.             // empty and remove the interrupt queue (if there is anything stored)
  312.                 DestroyFIFO(file_obj->pIrqListHandle);
  313.                
  314.                 ExFreePool(file_obj);
  315.                 Irp->Tail.Overlay.OriginalFileObject->FsContext = (FILE_OBJ *)NULL;
  316.         }
  317.  
  318.         KdPrint(("PCIVMEClose OK\n"));
  319.  
  320.     Irp->IoStatus.Status = STATUS_SUCCESS;
  321.         Irp->IoStatus.Information = 0;
  322.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
  323.  
  324.         return STATUS_SUCCESS;
  325. }
  326.  
  327. //------------------------------------------------------------------------
  328. // called at
  329. NTSTATUS PCIVMEShutdown(PDEVICE_OBJECT deviceObj, PIRP  irp  )
  330. {
  331.         UNREFERENCED_PARAMETER(irp);
  332.  
  333.     KdPrint(("PCIVMEShutdown()\n"));
  334.  
  335.         // deinit interfaces and interrupts
  336.         PCIVMEDeInitPCIADAs(deviceObj);
  337.  
  338.     KdPrint(("PCIVMEShutdown() OK\n"));
  339.  
  340.         return STATUS_SUCCESS;
  341. }
  342.  
  343. //------------------------------------------------------------------------
  344. // called at ioctl()
  345. NTSTATUS PCIVMEDeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
  346. {
  347.         PIO_STACK_LOCATION IrpStack;
  348.         int   nIndex;
  349.  
  350.         IrpStack  = IoGetCurrentIrpStackLocation(Irp);
  351.         nIndex    = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
  352.  
  353.     KdPrint(("PCIVMEDeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
  354.  
  355.         if (nIndex > CTL_INDEX(PCIVME_LAST_CTL_CODE))
  356.         {
  357.                 Irp->IoStatus.Status      = STATUS_UNSUCCESSFUL;
  358.                 Irp->IoStatus.Information = 0;
  359.                 IoCompleteRequest(Irp,IO_NO_INCREMENT);
  360.  
  361.         KdPrint(("PCIVMEDeviceControl() FAIL.\n"));
  362.  
  363.                 return STATUS_UNSUCCESSFUL;
  364.         }
  365.  
  366.         return ioctl[nIndex](deviceObj, Irp, IrpStack);
  367. }
  368.  
  369.  
  370. //------------------------------------------------------------------------
  371. // called at read()
  372. NTSTATUS PCIVMERead(PDEVICE_OBJECT device_Obj, PIRP Irp)
  373. {
  374.         NTSTATUS        Status        = STATUS_SUCCESS;
  375.         PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  376.         PVOID           pOutputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
  377.         LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
  378.         FILE_OBJ        *file_obj           = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  379.         DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  380.   PCIADA      *pciada             = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
  381.         register ULONG Address  = IrpStack->Parameters.Read.ByteOffset.LowPart  + file_obj->dwAccessBase;  
  382.         ULONG storeLength                   = 0;
  383.         PBOOLEAN pbPrevBusError;
  384.  
  385.         KdPrint(("PCIVMERead(%d)\n", file_obj->uwAssociatedVMEMM));
  386.  
  387.         // do here in between what has to be done -----------------
  388.   if (Address & file_obj->dwAddressMask)     // don't do unaligned transfers
  389.                 Status = STATUS_DATATYPE_MISALIGNMENT;
  390.         else
  391.         {
  392.                 register ULONG Length = IrpStack->Parameters.Read.Length;    
  393.                 register ULONG blockLength;
  394.                 register ULONG pageAddress;
  395.                 register ULONG toNextPage;
  396.                 KIRQL              oldIrql;
  397.  
  398.                 Length     &= ~file_obj->dwAddressMask; // align to integer increments
  399.                 storeLength = Length;
  400.                
  401.                 // lock other users out
  402.                 KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
  403.  
  404.                 // check for modifier
  405.                 if (pciada->bModifier != file_obj->bAddressModifier)
  406.                 {
  407.                         WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
  408.                         pciada->bModifier = file_obj->bAddressModifier;
  409.                 }
  410.                
  411.                 // do the read ---
  412.                 file_obj->bBusError = FALSE;
  413.                 pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
  414.                 while (Length)
  415.                 {
  416.                         pageAddress = Address & ~VME_ADR_MASK;
  417.                         if (pageAddress != pciada->dwVMEPage)
  418.                         {
  419.                                 WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
  420.                                 pciada->dwVMEPage = pageAddress;
  421.                         }
  422.  
  423.                         toNextPage  = (pageAddress + VME_ADR_MASK + 1) - Address;
  424.                         blockLength = (toNextPage < Length) ? toNextPage : Length;
  425.  
  426.                         KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
  427.                                                                                 Address, blockLength, Length));
  428.  
  429.                         file_obj->fRead(pOutputBuffer , blockLength, (PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)));
  430.  
  431.                         Length  -= blockLength;
  432.                         Address += blockLength;
  433.                         pOutputBuffer = (PVOID)((PUCHAR)pOutputBuffer + blockLength);
  434.                 }
  435.  
  436.                 // release the lock
  437.                 KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
  438.                 ExchangePointer(&pciada->pbBusError, pbPrevBusError);
  439.                 if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
  440.  
  441.             if (file_obj->bIncrement)  // only when increment to next is on
  442.                         *fileOffset =
  443.                                 RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
  444.         }
  445.         // do here in between what has to be done end -------------
  446.  
  447.         Irp->IoStatus.Status      = Status;  
  448.         Irp->IoStatus.Information = storeLength;  
  449.         IoCompleteRequest(Irp,IO_NO_INCREMENT);  
  450.  
  451.     KdPrint(("PCIVMERead(), Status = 0x%08x\n", Status));
  452.  
  453.         return Status;
  454. }
  455.  
  456.  
  457. //------------------------------------------------------------------------
  458. // called at write()
  459. NTSTATUS PCIVMEWrite(PDEVICE_OBJECT device_Obj, PIRP Irp)
  460. {
  461.         NTSTATUS        Status        = STATUS_SUCCESS;
  462.         PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  463.         PVOID           pInputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
  464.         LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
  465.         FILE_OBJ        *file_obj           = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  466.         DEVICE_EXT      *pDevExt          = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  467.   PCIADA      *pciada             = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
  468.         register ULONG Address  = IrpStack->Parameters.Write.ByteOffset.LowPart + file_obj->dwAccessBase;  
  469.         ULONG storeLength                   = 0;
  470.         PBOOLEAN pbPrevBusError;
  471.  
  472.         KdPrint(("PCIVMEWrite(%d)\n", file_obj->uwAssociatedVMEMM));
  473.  
  474.         // do here in between what has to be done -----------------
  475.   if (Address & file_obj->dwAddressMask)     // don't do unaligned transfers
  476.                 Status = STATUS_DATATYPE_MISALIGNMENT;
  477.         else
  478.         {
  479.                 register ULONG Length = IrpStack->Parameters.Write.Length;    
  480.                 register ULONG blockLength;
  481.                 register ULONG pageAddress;
  482.                 register ULONG toNextPage;
  483.                 KIRQL              oldIrql;
  484.  
  485.                 Length     &= ~file_obj->dwAddressMask; // align to integer increments
  486.                 storeLength = Length;
  487.                                                        // check for modifier
  488.                 // lock other users out
  489.                 KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
  490.  
  491.                 if (pciada->bModifier != file_obj->bAddressModifier)
  492.                 {
  493.                         WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
  494.                         pciada->bModifier = file_obj->bAddressModifier;
  495.                 }
  496.                
  497.                 // do the read ---
  498.                 file_obj->bBusError = FALSE;
  499.                 pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
  500.                 while (Length)
  501.                 {
  502.                         pageAddress = Address & ~VME_ADR_MASK;
  503.                         if (pageAddress != pciada->dwVMEPage)
  504.                         {
  505.                                 WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
  506.                                 pciada->dwVMEPage = pageAddress;
  507.                         }
  508.  
  509.                         toNextPage  = (pageAddress + VME_ADR_MASK + 1) - Address;
  510.                         blockLength = (toNextPage < Length) ? toNextPage : Length;
  511.  
  512.                         KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
  513.                                                                                 Address, blockLength, Length));
  514.  
  515.                         file_obj->fWrite((PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)) , blockLength, pInputBuffer);
  516.  
  517.                         Length  -= blockLength;
  518.                         Address += blockLength;
  519.                         pInputBuffer = (PVOID)((PUCHAR)pInputBuffer + blockLength);
  520.                 }
  521.  
  522.                 // release the lock
  523.                 KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
  524.                 ExchangePointer(&pciada->pbBusError, pbPrevBusError);
  525.                 if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
  526.  
  527.                 if (file_obj->bIncrement)  // only when increment to next is on
  528.                         *fileOffset =   RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
  529.         }
  530.         // do here in between what has to be done end -------------
  531.  
  532.         Irp->IoStatus.Status      = Status;  
  533.         Irp->IoStatus.Information = storeLength;  
  534.         IoCompleteRequest(Irp,IO_NO_INCREMENT);  
  535.  
  536.     KdPrint(("PCIVMEWrite(), Status = 0x%08x\n", Status));
  537.  
  538.         return Status;
  539. }
  540.  
  541. #ifdef DO_CLEANUP
  542. //------------------------------------------------------------------------
  543. // called at cancel of a path
  544. NTSTATUS PCIVMECancel(PDEVICE_OBJECT device_Obj, PIRP Irp)
  545. {
  546.         FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  547.         PIRP     pIrpCancel;
  548.  
  549.         KdPrint(("PCIVMECancel()\n"));
  550.  
  551.         // remove all queued IRPs of this file_obj
  552.         do
  553.         {
  554.                 pIrpCancel = RemoveIRPfromQueue(device_Obj, file_obj);
  555.  
  556.                 if (pIrpCancel == (PIRP)NULL)
  557.                 {
  558.                         IoReleaseCancelSpinLock(pIrpCancel->CancelIrql);
  559.                         break;
  560.                 }
  561.                 else
  562.                 {
  563.                         IoAcquireCancelSpinLock(pIrpCancel->CancelIrql);
  564.  
  565.                         // mark irp as not pending
  566.                         IoSetCancelRoutine(pIrpCancel, NULL);
  567.  
  568.                         IoReleaseCancelSpinLock(pIrpCancel->CancelIrql);
  569.  
  570.                         pIrpCancel->IoStatus.Status = STATUS_CANCELLED;
  571.                         pIrpCancel->IoStatus.Information = 0;
  572.                 }
  573.         } while (pIrpCancel != (PIRP)NULL);
  574.  
  575.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
  576.  
  577.         KdPrint(("PCIVMECancel(OK)\n"));
  578.  
  579.         return STATUS_SUCCESS;
  580. }
  581. #endif
  582.  
  583.  
  584. // http://read.pudn.com/downloads148/sourcecode/windows/vxd/640413/agp/agplib/init.c__.htm
  585. NTSTATUS  
  586. QueryBusInterface(  
  587.     IN PDEVICE_OBJECT DeviceObject,  
  588.     OUT PBUS_INTERFACE_STANDARD BusInterface  
  589.     )  
  590. /*++  
  591.  
  592. Routine Description:  
  593.  
  594.     Sends a query-interface IRP to the specified device object  
  595.     to obtain the BUS_INTERFACE_STANDARD interface.  
  596.  
  597. Arguments:  
  598.  
  599.     DeviceObject - Supplies the device object to send the BUS_INTERFACE_STANDARD to  
  600.  
  601.     BusInterface - Returns the bus interface  
  602.  
  603. Return Value:  
  604.  
  605.     STATUS_SUCCESS if successful  
  606.     NTSTATUS if unsuccessful  
  607.  
  608. --*/  
  609.    
  610. {  
  611.     PIRP Irp;  
  612.     KEVENT Event;  
  613.     PIO_STACK_LOCATION IrpSp;  
  614.     IO_STATUS_BLOCK IoStatusBlock;  
  615.     NTSTATUS Status;  
  616. //    ULONG ReturnLength;  
  617.    
  618.     KeInitializeEvent( &Event, NotificationEvent, FALSE );  
  619.     Irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,  
  620.                                         DeviceObject,  
  621.                                         NULL,  
  622.                                         0,  
  623.                                         NULL,  
  624.                                         &Event,  
  625.                                         &IoStatusBlock );  
  626.     if (Irp == NULL) {  
  627.         return(STATUS_INSUFFICIENT_RESOURCES);  
  628.     }  
  629.    
  630.     IrpSp = IoGetNextIrpStackLocation( Irp );  
  631.     ASSERT(IrpSp != NULL);  
  632.     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;  
  633.     IrpSp->MajorFunction = IRP_MJ_PNP;  
  634.     IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;  
  635.     IrpSp->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;  
  636.     IrpSp->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);  
  637.     IrpSp->Parameters.QueryInterface.Version = 1;  
  638.     IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE) BusInterface;  
  639.     IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;  
  640.    
  641.     Status = IoCallDriver(DeviceObject, Irp);  
  642.     if (Status == STATUS_PENDING) {  
  643.         KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );  
  644.         Status = Irp->IoStatus.Status;  
  645.     }  
  646.    
  647.     return(Status);  
  648. }  
  649.    
  650. //------------------------------------------------------------------------
  651. // search for pciada's
  652. //
  653.  
  654. NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
  655. {
  656.   PCI_SLOT_NUMBER   SlotNumber;
  657.   PCI_COMMON_CONFIG pci_config;
  658.   PBUS_INTERFACE_STANDARD busInterface;
  659.   PCIADA            *pciada;
  660.  
  661.   ULONG   propertyAddress, length;
  662.   USHORT  FunctionNumber, DeviceNumber;
  663.   int               *found;
  664.   int               i;
  665.   NTSTATUS          status;
  666.   int  BytesRead;
  667.   KdPrint(("SearchDevices()\n"));
  668.  
  669.   // prepare structures ----------------------------------------
  670.   found = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
  671.   *found = 0;
  672.   for (i = 0; i < PCIVME_MAX_PCIADA; i++)
  673.   {
  674.         pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  675.  
  676.         pciada->Bus                = -1;
  677.     pciada->Slot.u.AsULONG     = 0xFFFFFFFF;
  678.   }
  679.  
  680.   // search for pciada's ---------------------------------------
  681.   SlotNumber.u.bits.Reserved = 0;
  682.   busInterface = (PBUS_INTERFACE_STANDARD)ExAllocatePool(NonPagedPool,
  683.           sizeof(BUS_INTERFACE_STANDARD));
  684.   if (busInterface == NULL)
  685.   {
  686.           return STATUS_INSUFFICIENT_RESOURCES;
  687.   }
  688.   ((DEVICE_EXT*)(device_Obj->DeviceExtension))->busInterface = busInterface;
  689.   status = QueryBusInterface(device_Obj, busInterface);
  690.   BytesRead = busInterface->GetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, &pci_config, 0, PCI_COMMON_HDR_LENGTH);
  691.  
  692.   pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[0];
  693.  
  694.                 //http://www.hollistech.com/Resources/Misc%20articles/getbusdata.htm
  695.                 //IoGetDeviceProperty
  696.                 //There are other differnt methods to send a request to lower layer. One method is
  697.         //by sending IRP_MN_READ_CONFIG to lower driver. You will recieve
  698.         //PCI_COMMON_CONFIG structure.
  699.                 // http://msdn.microsoft.com/en-us/library/windows/hardware/ff536890(v=vs.85).aspx
  700.                 // http://www.rdos.net/svn/tags/V9.2.5/watcom/bld/src/win32/miniwdm/dev/wdmdev.c
  701.  
  702.                 if ((pci_config.VendorID    == PCIVME_VENDOR_ID) &&
  703.                         (pci_config.DeviceID    == PCIVME_DEVICE_ID) &&
  704.                         (pci_config.u.type0.SubSystemID == PCIVME_SUBSYS_ID) &&
  705.                         (pci_config.u.type0.SubVendorID == PCIVME_SUBVEN_ID) &&
  706.                         (pci_config.u.type0.BaseAddresses[2]))
  707.                 {
  708.                pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found];
  709.  
  710.                memcpy(&pciada->PCIDevice, &pci_config, sizeof(pci_config));
  711.        
  712.                    IoGetDeviceProperty(device_Obj,
  713.                            DevicePropertyBusNumber,
  714.                            sizeof(ULONG),
  715.                            (PVOID)&(pciada->Bus),
  716.                            &length);
  717.  
  718.                    IoGetDeviceProperty(device_Obj,
  719.                            DevicePropertyAddress,
  720.                            sizeof(ULONG),
  721.                            (PVOID)&propertyAddress,
  722.                            &length);
  723.                    //
  724.                    // For PCI, the DevicePropertyAddress has device number
  725.                    // in the high word and the function number in the low word.
  726.                    //
  727.                    FunctionNumber = (USHORT)((propertyAddress)& 0x0000FFFF);
  728.                    DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
  729.                    pciada->Slot.u.AsULONG = DeviceNumber;
  730.                    KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
  731.  
  732.                    (*found)++;
  733.                    if (*found >= PCIVME_MAX_PCIADA) return STATUS_SUCCESS;
  734.                        
  735.         }
  736.   KdPrint(("SearchDevices() found %d devices\n", (*found)));
  737.   return STATUS_SUCCESS;
  738. }
  739.  
  740. //---------------------------------------------------------------
  741. // function to call for bug fix of PLX9050 build in bug
  742. //
  743. NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
  744. {
  745.         // http://permalink.gmane.org/gmane.linux.kernel.pci/18419
  746.         DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
  747.         int i;
  748.         ULONG dwData;
  749.         PCIADA *pciada;
  750.         PBUS_INTERFACE_STANDARD busInterface;
  751.  
  752.         KdPrint(("PLX9050BugFix()\n"));
  753.         busInterface = DeviceExtension->busInterface;
  754.         for (i = 0; i < DeviceExtension->nPCIADAs; i++)
  755.         {
  756.                 pciada = &DeviceExtension->pciada[i];
  757.  
  758.                 if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[0]) & 0x80)
  759.                 {      
  760.                         KdPrint(("Changing address 0:0x%p with 4:0x%p\n",
  761.                                 pciada->PCIDevice.u.type0.BaseAddresses[0],
  762.                                 pciada->PCIDevice.u.type0.BaseAddresses[4]));
  763.  
  764.                         pciada->PCIDevice.u.type0.BaseAddresses[0] =           // exchange
  765.                                 pciada->PCIDevice.u.type0.BaseAddresses[4];
  766.                         pciada->PCIDevice.u.type0.BaseAddresses[4] = dwData;
  767.  
  768.                         if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0], 0x10, 4) != 4)
  769.                                 return STATUS_UNSUCCESSFUL;
  770.                        
  771.                         if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[4], 0x20, 4) != 4)
  772.                                 return STATUS_UNSUCCESSFUL;
  773.                        
  774.                 }
  775.      
  776.                 if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[1]) & 0x80)
  777.                 {
  778.                         KdPrint(("Changing address 1:0x%p with 5:0x%p\n",
  779.                                 pciada->PCIDevice.u.type0.BaseAddresses[1],
  780.                                 pciada->PCIDevice.u.type0.BaseAddresses[5]));
  781.  
  782.                   pciada->PCIDevice.u.type0.BaseAddresses[1] =           // exchange
  783.                                 pciada->PCIDevice.u.type0.BaseAddresses[5];
  784.                   pciada->PCIDevice.u.type0.BaseAddresses[5] = dwData;
  785.  
  786.                   if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1], 0x14, 4) != 4)
  787.                           return STATUS_UNSUCCESSFUL;
  788.                  
  789.                   if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5], 0x24, 4) != 4)
  790.                           return STATUS_UNSUCCESSFUL;
  791.                  
  792.                 }
  793.         }
  794.  
  795.         return STATUS_SUCCESS;
  796. }
  797.  
  798. static VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list)
  799. {                                                       // ShowResources
  800.         PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = list->PartialDescriptors;
  801.         ULONG nres = list->Count;
  802.         ULONG i;
  803.  
  804.         for (i = 0; i < nres; ++i, ++resource)
  805.         {                                               // for each resource
  806.                 ULONG type = resource->Type;
  807.  
  808.                 static char* namelow[] = {
  809.                         "CmResourceTypeNull",//                0   // ResType_All or ResType_None (0x0000)
  810.                         "CmResourceTypePort",//               1   // ResType_IO (0x0002)
  811.                         "CmResourceTypeInterrupt",//          2   // ResType_IRQ (0x0004)
  812.                         "CmResourceTypeMemory",//             3   // ResType_Mem (0x0001)
  813.                         "CmResourceTypeDma",//                4   // ResType_DMA (0x0003)
  814.                         "CmResourceTypeDeviceSpecific",//      5   // ResType_ClassSpecific (0xFFFF)
  815.                         "CmResourceTypeBusNumber",//          6   // ResType_BusNumber (0x0006)
  816.                         "CmResourceTypeMemoryLarge" //        7   // ResType_MemLarge (0x0007)
  817.                 };
  818.                 static char* namehigh[] = {
  819.                         //"CmResourceTypeNonArbitrated" ,//    128   // Not arbitrated if 0x80 bit set
  820.                         "CmResourceTypeConfigData",//       128   // ResType_Reserved (0x8000)
  821.                         "CmResourceTypeDevicePrivate",//    129   // ResType_DevicePrivate (0x8001)
  822.                         "CmResourceTypePcCardConfig",//     130   // ResType_PcCardConfig (0x8002)
  823.                         "CmResourceTypeMfCardConfig",//     131   // ResType_MfCardConfig (0x8003)
  824.                         "CmResourceTypeConnection" //       132   // ResType_Connection (0x8004)
  825.                 };
  826.  
  827.                 if (type<8) KdPrint((" [%d] type %s", type, type < arraysize(namelow) ? namelow[type] : "unknown"));
  828.                 if (type>127) KdPrint((" [%d] type %s", type, type-128 < arraysize(namehigh) ? namehigh[type-128] : "unknown"));
  829.                 switch (type)
  830.                 {                                       // select on resource type
  831.                 case CmResourceTypePort:
  832.                                 KdPrint((" start ADDR=0x%p  0x%8X%8.8lX length %X\n",
  833.                                 resource->u.Port.Start, resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
  834.                                 resource->u.Port.Length));
  835.                         break;
  836.                 case CmResourceTypeMemory:
  837.                         KdPrint((" %d start ADDR=0x%p \n", i,  resource->u.Memory.Start ));
  838.                         break;
  839.  
  840.                 case CmResourceTypeInterrupt:
  841.                         KdPrint(("  IRQL %d, vector %d, affinity %d\n",
  842.                                 resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
  843.                                 resource->u.Interrupt.Affinity));
  844.                         break;
  845.  
  846.                 case CmResourceTypeDma:
  847.                         KdPrint(("  channel %d, port %X\n",
  848.                                 resource->u.Dma.Channel, resource->u.Dma.Port));
  849.  
  850.                        
  851.                        
  852.                 }                                       // select on resource type
  853.         }                                               // for each resource
  854. }                                                       // ShowResources
  855.  
  856.  
  857. //------------------------------------------------------------------------
  858. //  reserve resources for PCIADAs
  859. //
  860. NTSTATUS PCIVMEExtractResources(PCIADA *pciada, PIRP irp)
  861. {
  862.         //PCM_RESOURCE_LIST pResourceList;
  863.         ///PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
  864.         PCM_PARTIAL_RESOURCE_LIST pPartialList = NULL;
  865.         PCM_PARTIAL_RESOURCE_LIST pListTranslated = NULL;
  866.         PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
  867.         int i;
  868.         int bug = 0;
  869.  
  870.         KdPrint(("PCIVMEExtractResources()\n"));
  871.  
  872.         ///pResourceList   = pList;
  873.         ///pFullDescriptor = pResourceList->List;
  874.         ///pPartialList    = &pFullDescriptor->PartialResourceList;
  875.         PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
  876.         if (stack->Parameters.StartDevice.AllocatedResources)
  877.         pPartialList = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
  878.         KdPrint(("Allocated Resources:------------------\n"));
  879.         ShowResources(pPartialList);
  880.        
  881.         int plcount = 0;
  882.         for (i=0; i<(int)pPartialList->Count; i++)
  883.         {
  884.                 pPartialDescriptor = &pPartialList->PartialDescriptors[i];
  885.                
  886.                 switch (pPartialDescriptor->Type)
  887.                 {
  888.                         case CmResourceTypeInterrupt:
  889.                                 pciada->Irql     = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
  890.                                 pciada->Vector   = pPartialDescriptor->u.Interrupt.Vector;
  891.                                 pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
  892.  
  893.                                 KdPrint(("AllocatedResources Irq    : Irql: %d, Vector: %d, Affinity: %d\n",
  894.                                         pciada->Irql, pciada->Vector, pciada->Affinity));
  895.                                 break;
  896.                         case CmResourceTypeDma:
  897.                                 KdPrint(("AllocatedResources Dma    : \n"));
  898.                                 break;
  899.                         case CmResourceTypePort:
  900.  
  901.                                 KdPrint(("AllocatedResources Port   : 0x%p\n", pPartialDescriptor->u.Port.Start));
  902.                                 break;
  903.                         case CmResourceTypeMemory:
  904.                                 // special handling of PLXBUG here because of WIN2000
  905.                                 // WIN2000 doesn't recognize late address changes
  906.                                 if (!bug)
  907.                                 {
  908.                                         if (plcount == 0)
  909.                                         {
  910.                                                 pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  911.  
  912.                                                 if (pciada->pvPhysLcr.LowPart & 0x80) {
  913.                                                         bug = 1;
  914.                                                         KdPrint(("AllocatedResources PLXBug\n"));
  915.                                                 }
  916.                                         }
  917.                                 }
  918.                                 else
  919.                                 {
  920.                                         if (plcount == 3)
  921.                                                 pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  922.                                 }
  923.  
  924.                                 if (plcount == 2){
  925.                                         pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
  926.                                         KdPrint(("PCIVMEExtractResources() IFR=0x%p \n", pciada->pvPhysIfr));
  927.                                 }
  928.                                 KdPrint(("[%d] AllocatedResources Memory : 0x%p\n", plcount, (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
  929.                                 break;
  930.                 }
  931.                 if (pPartialDescriptor->Type < 8) plcount++;
  932.         }
  933.  
  934.         KdPrint(("PCIVMEExtractResources() LCR=0x%p IFR=0x%p \n", pciada->pvPhysLcr, pciada->pvPhysIfr));
  935.  
  936.         if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
  937.                 pListTranslated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
  938.         KdPrint(("Translated Resources:------------------\n"));
  939.         ShowResources(pListTranslated);
  940.         plcount = 0;
  941.         bug     = 0;
  942.         for (i = 0; i<(int)pPartialList->Count; i++)
  943.         {
  944.                 pPartialDescriptor = &pListTranslated->PartialDescriptors[i];
  945.  
  946.                 switch (pPartialDescriptor->Type)
  947.                 {
  948.                 case CmResourceTypeInterrupt:
  949.                         pciada->Irql = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
  950.                         pciada->Vector = pPartialDescriptor->u.Interrupt.Vector;
  951.                         pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
  952.  
  953.                         KdPrint(("AllocatedResourcesTranslated Irq    : Irql: %d, Vector: %d, Affinity: %d\n",
  954.                                 pciada->Irql, pciada->Vector, pciada->Affinity));
  955.                         break;
  956.                 case CmResourceTypeDma:
  957.                         KdPrint(("AllocatedResourcesTranslated Dma    : \n"));
  958.                         break;
  959.                 case CmResourceTypePort:
  960.  
  961.                         KdPrint(("AllocatedResourcesTranslated Port   : 0x%p\n", pPartialDescriptor->u.Port.Start));
  962.                         break;
  963.                 case CmResourceTypeMemory:
  964.                         // special handling of PLXBUG here because of WIN2000
  965.                         // WIN2000 doesn't recognize late address changes
  966.                         if (!bug)
  967.                         {
  968.                                 if (plcount == 0)
  969.                                 {
  970.                                         pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  971.                                         KdPrint(("0 PCIVMEExtractResources() LCR=0x%p \n", pciada->pvPhysLcr));
  972.                                         if (pciada->pvPhysLcr.LowPart & 0x80) {
  973.                                                 bug = 1;
  974.                                                 KdPrint(("AllocatedResourcesTranslated PLXBug\n"));
  975.                                         }
  976.                                 }
  977.                         }
  978.                         else
  979.                         {
  980.                                 if (plcount == 3){
  981.                                         pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
  982.                                         KdPrint(("3 PCIVMEExtractResources() LCR=0x%p \n", pciada->pvPhysLcr));
  983.                                 }
  984.                         }
  985.  
  986.                         if (plcount == 2){
  987.                                 pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
  988.                                 KdPrint(("2 PCIVMEExtractResources() IFR=0x%p \n", pciada->pvPhysIfr));
  989.                         }
  990.  
  991.                         KdPrint(("[%d] AllocatedResourcesTranslated Memory : 0x%p\n", plcount, (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
  992.                         break;
  993.                 }
  994.                 if (pPartialDescriptor->Type < 8) plcount++;
  995.         }
  996.  
  997.  
  998.  
  999.         if (pciada->Irql == 0)
  1000.                 return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
  1001.  
  1002.         KdPrint(("PCIVMEExtractResources() Translated LCR=0x%p IFR=0x%p \n", pciada->pvPhysLcr, pciada->pvPhysIfr));
  1003.  
  1004.         return STATUS_SUCCESS;
  1005. }
  1006.  
  1007. NTSTATUS PCIVMEReserveResources(PDEVICE_OBJECT device_Obj, PIRP irp)
  1008. {
  1009.         //PCM_RESOURCE_LIST pList = NULL;
  1010.         NTSTATUS result = STATUS_SUCCESS;
  1011.         int i;
  1012.         DEVICE_EXT *pDevExt = (DEVICE_EXT*)(device_Obj->DeviceExtension);
  1013.         int nPCIADAs = pDevExt->nPCIADAs;
  1014.         PCIADA *pciada;
  1015.     UNICODE_STRING DriverClassName;
  1016.    
  1017.         KdPrint(("PCIVMEReserveResources()\n"));
  1018.  
  1019.         // prepare resource claiming
  1020.         //RtlInitUnicodeString(&DriverClassName, L"PCICC32");
  1021.         RtlInitUnicodeString(&DriverClassName, L"PCIVME");
  1022.         // cycle through all busses and slots assigned to PCIADAs
  1023.         for (i = 0; i < nPCIADAs; i++)
  1024.     {
  1025.                 pciada = &pDevExt->pciada[i];
  1026.  
  1027.                 //result = HalAssignSlotResources(NULL, &DriverClassName, device_Obj->DriverObject, device_Obj,
  1028.                 //      PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, &pList);
  1029.                 /*
  1030.                 result = IoReportDetectedDevice(device_Obj->DriverObject, PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, pList, NULL, FALSE, &device_Obj);
  1031.                 if (result != STATUS_SUCCESS){
  1032.                         KdPrint(("PCIVMEReserveResources(0x%08x) HalAssignSlotResources  ***ERROR*** faliure to get slot information\n", result));
  1033.                         break;
  1034.                 }
  1035.                 */
  1036.                 result = PCIVMEExtractResources(pciada, irp);
  1037.  
  1038.                 if (result != STATUS_SUCCESS){
  1039.                         KdPrint(("PCIVMEReserveResources(0x%08x) PCIVMEExtractResources\n", result));
  1040.                         break;
  1041.                 }
  1042.         }
  1043.  
  1044.         // its my part to free allocated resources
  1045.         //if (pList != NULL) ExFreePoolWithTag(pList,'nepo');
  1046.  
  1047.         KdPrint(("PCIVMEReserveResources(0x%08x)\n", result));
  1048.  
  1049.         return result;
  1050. };
  1051.  
  1052.  
  1053. //------------------------------------------------------------------------
  1054. //  translate memory resources to neutral for PCIADAs
  1055. //
  1056. NTSTATUS PCIVMETranslateBusAddresses(PDEVICE_OBJECT device_Obj,  PIRP irp)
  1057. {
  1058.         int              i;
  1059.         NTSTATUS         result = STATUS_SUCCESS;
  1060.         int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
  1061.         ULONG            memType0, memType2;
  1062.         PCIADA           *pciada;
  1063.         PCM_PARTIAL_RESOURCE_LIST pPartialList = NULL;
  1064.         PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
  1065.         if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
  1066.        pPartialList = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
  1067.  
  1068.    
  1069.         for (i = 0; i < nPCIADAs; i++)
  1070.         {
  1071.       pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  1072.  
  1073.           memType0 = memType2 = 0;
  1074.           /*
  1075.           if (!(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysLcr, &memType0,
  1076.                                                                &pciada->pvPhysLcr)) ||
  1077.               !(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysIfr, &memType2,
  1078.                                                                &pciada->pvPhysIfr)))
  1079.           {
  1080.                   result = STATUS_UNSUCCESSFUL;
  1081.                   break;
  1082.           }
  1083.           */
  1084.           KdPrint(("PCIADA %d TranslateBusAddresseses() -- no translation is made\n", i));
  1085.  
  1086.           if ((memType0) || (memType2))
  1087.           {
  1088.                   result = STATUS_UNSUCCESSFUL;
  1089.                   break;
  1090.           }
  1091.         }
  1092.    
  1093.         return result;
  1094. }
  1095.  
  1096. //------------------------------------------------------------------------
  1097. //  map address spaces to virtual addresses
  1098. //
  1099. NTSTATUS PCIVMEMapIOspace(PDEVICE_OBJECT device_Obj)
  1100. {
  1101.         int              i;
  1102.         DEVICE_EXT       *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
  1103.         int                              nPCIADAs = pDevExt->nPCIADAs;
  1104.         PCIADA           *pciada;
  1105.  
  1106.         KdPrint(("PCIVMEMapIOspace()\n"));
  1107.  
  1108.         for (i = 0; i < nPCIADAs; i++)
  1109.         {
  1110.        pciada = &pDevExt->pciada[i];
  1111.  
  1112.        if ((pciada->pvVirtLcr = MmMapIoSpace(pciada->pvPhysLcr, LCR_SPACE, FALSE)) == NULL)
  1113.           return STATUS_UNSUCCESSFUL;
  1114.        if ((pciada->pvVirtIfr = MmMapIoSpace(pciada->pvPhysIfr, IFR_SPACE, FALSE)) == NULL)
  1115.           return STATUS_UNSUCCESSFUL;
  1116.  
  1117.            KdPrint(("PCIADA %d: LCR 0x%08x IFR 0x%08x\n",
  1118.                                          i, pciada->pvVirtLcr, pciada->pvVirtIfr));
  1119.  
  1120.            pciada->pwIntCSR = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x4C);
  1121.            pciada->pwCntrl  = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x50);
  1122.         }
  1123.  
  1124.         return STATUS_SUCCESS;
  1125. }
  1126.  
  1127.  
  1128. //------------------------------------------------------------------------
  1129. //  initializes and registers a DPC routine for each pciada
  1130. //
  1131. NTSTATUS InitializeCustomDPCObjects(PDEVICE_OBJECT device_object)
  1132. {
  1133.         int              i;
  1134.         int nPCIADAs = ((DEVICE_EXT*)(device_object->DeviceExtension))->nPCIADAs;
  1135.         PCIADA           *pciada;
  1136.  
  1137.         KdPrint(("InitializeCustomDPCObject()\n"));
  1138.  
  1139.         for (i = 0; i < nPCIADAs; i++)
  1140.         {
  1141.                 pciada = &((DEVICE_EXT*)(device_object->DeviceExtension))->pciada[i];
  1142.                 KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
  1143.         }
  1144.  
  1145.         return STATUS_SUCCESS;
  1146. }
  1147.  
  1148. //------------------------------------------------------------------------
  1149. //  initializes the queue for storing IRPs waiting for vectors
  1150. //
  1151. NTSTATUS InitializeIRPQueue(PDEVICE_OBJECT device_Obj)
  1152. {
  1153.         DEVICE_EXT *pDevExt = ((DEVICE_EXT*)(device_Obj->DeviceExtension));
  1154.  
  1155.         KdPrint(("InitializeIRPQueue()\n"));
  1156.  
  1157.         KeInitializeSpinLock(&pDevExt->IRPLock);
  1158.         InitializeListHead(&pDevExt->IRPList);
  1159.  
  1160.         return STATUS_SUCCESS;
  1161. }
  1162.  
  1163. //------------------------------------------------------------------------
  1164. // init structures a.s.o.
  1165. //
  1166. VOID PCIVMESoftInit(PDEVICE_OBJECT device_Obj)
  1167. {
  1168.         int i;
  1169.         PCIADA *pciada;
  1170.  
  1171.         for (i = 0; i < PCIVME_MAX_PCIADA; i++)
  1172.         {
  1173.                 pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
  1174.  
  1175.                 pciada->pvPhysLcr.QuadPart = pciada->pvPhysIfr.QuadPart = 0;
  1176.                 pciada->pvVirtLcr = pciada->pvVirtIfr = NULL;
  1177.  
  1178.                 pciada->bConnected     = FALSE;   // connection still not verified
  1179.                 pciada->bWordMode      = TRUE;
  1180.                 pciada->bSysControl    = FALSE;
  1181.                 pciada->wModuleNumber  = 0xFFFF;
  1182.                 pciada->wFPGAVersion   = 0xFFFF;
  1183.                 pciada->wModuleType    = 1;       // always VMEMM
  1184.  
  1185.                 pciada->InterruptObject = NULL;
  1186.                 pciada->Irql                    = 0;
  1187.                 pciada->Vector          = 0;
  1188.                 pciada->Affinity                = 0;
  1189.  
  1190.                 pciada->dwLinkCount     = 0;
  1191.                                        
  1192.                 KeInitializeSpinLock(&pciada->IrqListLock);
  1193.                 KeInitializeSpinLock(&pciada->AccessLock);
  1194.  
  1195.                 InitializeListHead(&pciada->IrqListList);  // start of list of irq fifos
  1196.  
  1197.                 pciada->nInterruptHandlers = 0;
  1198.         }
  1199.  
  1200.         // no vmemm associated to any PCIADA
  1201.         for (i = 0; i < PCIVME_MAX_VMEMM; i++)
  1202.           ((DEVICE_EXT*)(device_Obj->DeviceExtension))->vmemm[i] = NULL;
  1203. }
  1204.  
  1205. NTSTATUS OnRequestComplete(PDEVICE_OBJECT fdo, PIRP Irp, PKEVENT pev)
  1206. {
  1207.         UNREFERENCED_PARAMETER(fdo);
  1208.         UNREFERENCED_PARAMETER(Irp);
  1209.         KeSetEvent(pev, 0, FALSE);
  1210.         return STATUS_MORE_PROCESSING_REQUIRED;
  1211. }
  1212.  
  1213. NTSTATUS CompleteRequest(PIRP Irp, NTSTATUS status, ULONG_PTR Information)
  1214. {
  1215.         Irp->IoStatus.Status = status;
  1216.         Irp->IoStatus.Information = Information;
  1217.         IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1218.         return status;
  1219. }
  1220. NTSTATUS ForwardAndWait(PDEVICE_OBJECT fdo, PIRP Irp)
  1221. {
  1222.         KEVENT event;
  1223.         KeInitializeEvent(&event, NotificationEvent, FALSE);
  1224.         IoCopyCurrentIrpStackLocationToNext(Irp);
  1225.         IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete, (PVOID)&event, TRUE, TRUE, TRUE);
  1226.         PDEVICE_EXT pdx = (PDEVICE_EXT ) fdo->DeviceExtension;
  1227.         IoCallDriver(pdx->LowerDeviceObject, Irp);
  1228.         KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1229.         return Irp->IoStatus.Status;
  1230. }
  1231.  
  1232. NTSTATUS HandleStartDevice(PDEVICE_OBJECT fdo, PIRP Irp)
  1233. {
  1234.         PIO_STACK_LOCATION stack;
  1235.         Irp->IoStatus.Status = STATUS_SUCCESS;
  1236.         NTSTATUS status = ForwardAndWait(fdo, Irp);
  1237.         if (!NT_SUCCESS(status))
  1238.                 return CompleteRequest(Irp, status, Irp->IoStatus.Information);
  1239.        
  1240.         stack = IoGetCurrentIrpStackLocation(Irp);
  1241.         status = PCIVMEStartDevice(fdo, Irp);
  1242.         return CompleteRequest(Irp, status, Irp->IoStatus.Information);
  1243. }
  1244.  
  1245.  
  1246. NTSTATUS DefaultPnpHandler(PDEVICE_OBJECT fdo, PIRP Irp)
  1247. {
  1248.         IoSkipCurrentIrpStackLocation(Irp);
  1249.         PDEVICE_EXT pdx = (PDEVICE_EXT )fdo->DeviceExtension;
  1250.         return IoCallDriver(pdx->LowerDeviceObject, Irp);
  1251. }
  1252.  
  1253. NTSTATUS HandleStopDevice(PDEVICE_OBJECT fdo, PIRP Irp)
  1254. {
  1255.         IoSkipCurrentIrpStackLocation(Irp);
  1256.         UNICODE_STRING symbol_name;
  1257.         RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
  1258.     // delete the symbolicLink in the registry
  1259.         IoDeleteSymbolicLink(&symbol_name);
  1260.         DEVICE_EXT *ext = (DEVICE_EXT*)(fdo->DeviceExtension);
  1261.         // delete the busInterface and deviceObject
  1262.         if (ext->busInterface) {
  1263.                 (*ext->busInterface->InterfaceDereference)(ext->busInterface->Context);
  1264.                 ext->busInterface = NULL;
  1265.         }
  1266.         if (ext->LowerDeviceObject) IoDetachDevice(ext->LowerDeviceObject);
  1267.         IoDeleteDevice(fdo);
  1268.         KdPrint(("HandleStopDevice (OK)\n"));
  1269.         return STATUS_SUCCESS;
  1270. }
  1271.  
  1272.  
  1273. NTSTATUS PCIVMEDispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)
  1274. {
  1275.         PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  1276.         ULONG fcn = stack->MinorFunction;
  1277.         static char* pnpname[] = {
  1278.                 "IRP_MN_START_DEVICE",
  1279.                 "IRP_MN_QUERY_REMOVE_DEVICE",
  1280.                 "IRP_MN_REMOVE_DEVICE",
  1281.                 "IRP_MN_CANCEL_REMOVE_DEVICE",
  1282.                 "IRP_MN_STOP_DEVICE",
  1283.                 "IRP_MN_QUERY_STOP_DEVICE",
  1284.                 "IRP_MN_CANCEL_STOP_DEVICE",
  1285.                 "IRP_MN_QUERY_DEVICE_RELATIONS",
  1286.                 "IRP_MN_QUERY_INTERFACE",
  1287.                 "IRP_MN_QUERY_CAPABILITIES",
  1288.                 "IRP_MN_QUERY_RESOURCES",
  1289.                 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
  1290.                 "IRP_MN_QUERY_DEVICE_TEXT",
  1291.                 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
  1292.                 "",
  1293.                 "IRP_MN_READ_CONFIG",
  1294.                 "IRP_MN_WRITE_CONFIG",
  1295.                 "IRP_MN_EJECT",
  1296.                 "IRP_MN_SET_LOCK",
  1297.                 "IRP_MN_QUERY_ID",
  1298.                 "IRP_MN_QUERY_PNP_DEVICE_STATE",
  1299.                 "IRP_MN_QUERY_BUS_INFORMATION",
  1300.                 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
  1301.                 "IRP_MN_SURPRISE_REMOVAL",
  1302.                 "IRP_MN_QUERY_LEGACY_BUS_INFORMATION",
  1303.         };
  1304.  
  1305.         if (fcn < arraysize(pnpname))
  1306.                 KdPrint(("PCIVMEDispatchPnp  - IRP_MJ_PNP (%s)\n", pnpname[fcn]));
  1307.         else
  1308.                 KdPrint(( "PCIVMEDispatchPnp - IRP_MJ_PNP (%2.2X)\n", fcn));
  1309.  
  1310.         static NTSTATUS(*fcntab[])(PDEVICE_OBJECT, PIRP) = {
  1311.                 HandleStartDevice,        // IRP_MN_START_DEVICE
  1312.         //      DefaultPnpHandler,        // IRP_MN_QUERY_REMOVE_DEVICE
  1313.                 HandleStopDevice          // IRP_MN_REMOVE_DEVICE
  1314.         };
  1315.  
  1316.         if (fcn >= arraysize(fcntab))
  1317.                 return DefaultPnpHandler(fdo, Irp);
  1318.         return (*fcntab[fcn])(fdo, Irp);
  1319. }
  1320.  
  1321.  
  1322. NTSTATUS PCIVMEStartDevice(PDEVICE_OBJECT device_object, PIRP irp){
  1323.         NTSTATUS result = STATUS_SUCCESS;
  1324.         int            nPCIADAs;                                // count of PCIADAs
  1325.         DEVICE_EXT     *DeviceExtension = NULL;
  1326.         DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
  1327.         // init pciada structures ------------------------------------
  1328.         PCIVMESoftInit(device_object);
  1329.  
  1330.         // search for PCIADAs ----------------------------------------
  1331.         result = SearchDevices(device_object);
  1332.         nPCIADAs = DeviceExtension->nPCIADAs;
  1333.  
  1334.         if ((result != STATUS_SUCCESS) || !(nPCIADAs))
  1335.         {
  1336.                 KdPrint(("PCIVMEStartDevice Device not found\n"));
  1337.                 PCIVMEUnload(DeviceExtension->driverObj);
  1338.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1339.         }
  1340.  
  1341.         // request exclusive ownership of .. ---------------------------------
  1342.         if ((result = PCIVMEReserveResources(device_object, irp)) != STATUS_SUCCESS)
  1343.         {
  1344.                 KdPrint(("PCIVMEStartDevice Resource not reserved PCIVMEReserveResources \n"));
  1345.                 PCIVMEUnload(DeviceExtension->driverObj);
  1346.                 return result;
  1347.         }
  1348.         else
  1349.                 DeviceExtension->nInitState++;
  1350.         // fix PLX9050 Bug -------------------------------------------
  1351.         if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
  1352.         {
  1353.                 KdPrint(("PCIVMEStartDevice PLX9050BugFix\n"));
  1354.                 PCIVMEUnload(DeviceExtension->driverObj);
  1355.                 return result;
  1356.         }
  1357.  
  1358.         DeviceExtension->nInitState += 2;
  1359.         /*
  1360.         // translate BUS relative addresses ----------------------------------
  1361.         if ((result = PCIVMETranslateBusAddresses(device_object,irp)) != STATUS_SUCCESS)
  1362.         {
  1363.                 PCIVMEUnload(DeviceExtension->driverObj);
  1364.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1365.         }
  1366.         else
  1367.                 DeviceExtension->nInitState++;
  1368.  
  1369.        
  1370.         // translate Interrupt Resources used --------------------------------
  1371.         if ((result = PCIVMETranslateInterrupts(device_object)) != STATUS_SUCCESS)
  1372.         {
  1373.                 PCIVMEUnload(DeviceExtension->driverObj);
  1374.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1375.         }
  1376.         else
  1377.                 DeviceExtension->nInitState++;
  1378.         */
  1379.  
  1380.         // map address spaces to virtual addresses ---------------------------
  1381.         if ((result = PCIVMEMapIOspace(device_object)) != STATUS_SUCCESS)
  1382.         {
  1383.                 PCIVMEUnload(DeviceExtension->driverObj);
  1384.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1385.         }
  1386.         else
  1387.                 DeviceExtension->nInitState++;
  1388.  
  1389.         // initialze my custom DPC objects -----------------------------------
  1390.         if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
  1391.         {
  1392.                 PCIVMEUnload(DeviceExtension->driverObj);
  1393.                 return result;
  1394.         }
  1395.         else
  1396.                 DeviceExtension->nInitState++;
  1397.  
  1398.         // initialze the queue for IRPs waiting for vectors ------------------
  1399.         if ((result = InitializeIRPQueue(device_object)) != STATUS_SUCCESS)
  1400.         {
  1401.                 PCIVMEUnload(DeviceExtension->driverObj);
  1402.                 return result;
  1403.         }
  1404.         else
  1405.                 DeviceExtension->nInitState++;
  1406.  
  1407.         // connect interrupts to service routines ----------------------------
  1408.         if ((result = PCIVMEConnectInterrupt(device_object)) != STATUS_SUCCESS)
  1409.         {
  1410.                 PCIVMEUnload(DeviceExtension->driverObj);
  1411.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1412.         }
  1413.         else
  1414.                 DeviceExtension->nInitState++;
  1415.  
  1416.         // scan all connected VMEMM for info and later use -------------------
  1417.         if ((result = PCIVMEScanVMEMM(device_object)) != STATUS_SUCCESS)
  1418.         {
  1419.                 PCIVMEUnload(DeviceExtension->driverObj);
  1420.                 return STATUS_DEVICE_DOES_NOT_EXIST;
  1421.         }
  1422.  
  1423.         device_object->Flags &= ~DO_DEVICE_INITIALIZING;
  1424.         return result;
  1425. }
  1426.  
  1427. NTSTATUS PCIVMEAddDevice(PDRIVER_OBJECT driverObj,  PDEVICE_OBJECT  pdo)
  1428.         {                                                       // AddDevice
  1429.        
  1430.         UNICODE_STRING device_name;
  1431.         UNICODE_STRING symbol_name;
  1432.         NTSTATUS result = STATUS_SUCCESS;
  1433.         //int            nPCIADAs;                              // count of PCIADAs
  1434.         DEVICE_EXT     *DeviceExtension = NULL;
  1435.         PDEVICE_OBJECT device_object;
  1436.         RtlInitUnicodeString(&device_name, L"\\Device\\PCIVME");
  1437.         KdPrint(("PCIVME AddDevice() v%d.%d\n", (DRIVER_VERSION >> 16) & 0xff, DRIVER_VERSION & 0xff));
  1438.         /* DeviceObject durch IO-Manager erzeugen */
  1439.         result = IoCreateDevice( driverObj,           // DriverObject received by the DriverEntry Call
  1440.                                                          sizeof(DEVICE_EXT),  // required Memory for the DeviceExtension
  1441.                                                          &device_name,        // Name of the device in the device-Directory
  1442.                                                          FILE_DEVICE_UNKNOWN, // Device-ID              
  1443.                                                          0,                   // Device-Characteristics normal 0
  1444.                                                          FALSE,               // TRUE : one Thread can open the driver
  1445.                                                          &device_object);     // DeviceObject returned from the IO-Manager
  1446.  
  1447.         // defines how the data are handled between user / kernel Adress-Space  
  1448.         device_object->Flags |= DO_DIRECT_IO;
  1449.  
  1450. #if 0
  1451.         // register the shutdown notification entry
  1452.     IoRegisterShutdownNotification(device_object);
  1453. #endif
  1454.  
  1455.         // anounce driver as symbolic device ---------------------------------
  1456.         if (result == STATUS_SUCCESS)
  1457.         {
  1458.                 /* now the symbolic Link is created. If there is no S.L. a program cannot connect to the driver */
  1459.                 RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
  1460.                 result = IoCreateSymbolicLink(&symbol_name,&device_name);
  1461.                 if (result != STATUS_SUCCESS)
  1462.                 {
  1463.        
  1464.                         IoDeleteDevice(device_object);
  1465.                         return result;
  1466.                 }
  1467.         }
  1468.         else
  1469.                 return result;
  1470.  
  1471.  
  1472.         DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
  1473.  
  1474.         DeviceExtension->actualIrp  = NULL;
  1475.         DeviceExtension->driverObj  = driverObj;
  1476.         DeviceExtension->nInitState = 0;
  1477.  
  1478.        
  1479.         DeviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack(device_object, pdo);
  1480.     KdPrint(("AddDevice() OK.\n"));
  1481.  
  1482.         return result;
  1483. }
  1484.  
  1485. //------------------------------------------------------------------------
  1486. // the ultimate starting point of a driver
  1487. NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
  1488. {
  1489.         UNREFERENCED_PARAMETER(regPath);
  1490.        
  1491.         KdPrint(("PCIVME DriverEntry() v%d.%d\n", (DRIVER_VERSION >> 16) & 0xff, DRIVER_VERSION & 0xff));
  1492.  
  1493.         driverObj->DriverUnload = PCIVMEUnload;
  1494.         driverObj->DriverExtension->AddDevice = PCIVMEAddDevice;
  1495.         driverObj->MajorFunction[IRP_MJ_CREATE] = PCIVMEOpen;
  1496.         driverObj->MajorFunction[IRP_MJ_CLOSE] = PCIVMEClose;
  1497.         driverObj->MajorFunction[IRP_MJ_READ] = PCIVMERead;
  1498.         driverObj->MajorFunction[IRP_MJ_WRITE] = PCIVMEWrite;
  1499.         driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PCIVMEDeviceControl;
  1500. #ifdef DO_CLEANUP
  1501.         driverObj->MajorFunction[IRP_MJ_CLEANUP] = PCIVMECancel;
  1502. #endif
  1503.         driverObj->MajorFunction[IRP_MJ_SHUTDOWN] = PCIVMEShutdown;
  1504.         driverObj->MajorFunction[IRP_MJ_PNP] = PCIVMEDispatchPnp;
  1505.         return  STATUS_SUCCESS;;
  1506. }