Subversion Repositories f9daq

Rev

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

  1. //-------------------------------------------------------------------------
  2. // WINNT driver for PCICC32 interface from ARW Elektronik, Germany ---------
  3. // the ioctl functions
  4. //
  5. // (c) 1999-2002 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. // what                                            who          when
  16. // started                                         AR           03.07.1999
  17. // first release 1.0                                                       AR                   17.10.1999
  18. // added access to PLX LC-Register                 AR           30.03.2001
  19. // changed making procedure (only VCC > 6.0)       AR           30.05.2002
  20. // multiple interrupt enable allowed               AR           01.06.2002
  21. // added KeSynchronizeExecution for interrupt sync AR           16.06.2002
  22. // extended ioctl_irq_status_kernel                AR           18.06.2002
  23. //
  24.  
  25. //-------------------------------------------------------------------------
  26. // INCLUDES
  27. //
  28. #include <ntddk.h>
  29. #include <devioctl.h>
  30. #include <pcicc32_drv.h>
  31. #include <pcicc32.h>
  32. #include <pcicc32_v.h>
  33. #include <pcicc32_io.h>
  34. #include <pcicc32_local.h>
  35. #include <pcicc32_i.h>
  36.  
  37. //------------------------------------------------------------------------
  38. // DEFINES
  39. //
  40.  
  41. // buffers usage must match the corresponding ioctl code!
  42. #define SET_BUFFERS_METHOD_OUT_DIRECT \
  43. {\
  44.         InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
  45.         OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
  46.         pInputBuffer  = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
  47.         pOutputBuffer = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
  48. }
  49.  
  50. #define SET_BUFFERS_METHOD_IN_DIRECT \
  51. {\
  52.         InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
  53.         OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
  54.         pInputBuffer  = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
  55.         pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
  56. }
  57.  
  58. #define SET_BUFFERS_METHOD_BUFFERED \
  59. {\
  60.         InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
  61.         OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
  62.         pInputBuffer  = pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
  63. }
  64.  
  65. #define COMPLETE_REQUEST \
  66. {\
  67.         if (Status != STATUS_PENDING)\
  68.         {\
  69.                 Irp->IoStatus.Status      = Status; \
  70.                 Irp->IoStatus.Information = irp_info; \
  71.                 IoCompleteRequest(Irp,IO_NO_INCREMENT); \
  72.         }\
  73. }
  74.  
  75. // compatibilty issues to WIN95 driver calls
  76. #ifndef WORD
  77. #define WORD USHORT
  78. #endif
  79.  
  80. #ifndef DWORD
  81. #define DWORD ULONG
  82. #endif
  83.  
  84. #ifndef BYTE
  85. #define BYTE UCHAR
  86. #endif
  87.  
  88. #ifndef BOOL
  89. #define BOOL BOOLEAN
  90. #endif
  91.  
  92.  
  93. //-------------------------------------------------------------------------
  94. // TYPEDEFS
  95. //
  96. typedef struct
  97. {
  98.         FILE_OBJ    *file_obj;
  99.         PCIADA      *pciada;
  100.         PCICC32_IRQ_RESPONSE *pIrqStatus;
  101.         PIRP        *Irp;
  102.         ULONG       *irp_info;
  103.         NTSTATUS    *Status;
  104. } IOCTL_IRQ_STATUS_CONTEXT;
  105.  
  106. //--------------------------------------------------------------------------
  107. // LOCAL FUNCTIONS
  108. //
  109.  
  110. //--------------------------------------------------------------------------
  111. // fast read or write functions - portable -
  112. static void readWord(void *to, void *from)
  113. {
  114.         *(PUSHORT)to = READ_REGISTER_USHORT((PUSHORT)from);
  115. }
  116.  
  117. static void readLong(void *to, void *from)
  118. {
  119.         *(PULONG)to = READ_REGISTER_ULONG((PULONG)from);
  120. }
  121.  
  122. static void writeWord(void *to, void *from)
  123. {
  124.         WRITE_REGISTER_USHORT((PUSHORT)to, *(PUSHORT)from);
  125. }
  126.  
  127. static void writeLong(void *to, void *from)
  128. {
  129.         WRITE_REGISTER_ULONG((PULONG)to, *(PULONG)from);
  130. }
  131.  
  132. //------------------------------------------------------------------------
  133. // init the interface with build in and user supplied constants
  134. static BOOLEAN InitInterface(PVOID pvLcr, PVOID pvIfr)
  135. {
  136.   UNREFERENCED_PARAMETER(pvLcr);
  137.   UNREFERENCED_PARAMETER(pvIfr);
  138.   return TRUE;
  139. }
  140.  
  141. // deinit the interface with user supplied and build in constants
  142. static BOOLEAN DeInitInterface(PVOID pvLcr, PVOID pvIfr)
  143. {
  144.   UNREFERENCED_PARAMETER(pvLcr);
  145.   UNREFERENCED_PARAMETER(pvIfr);
  146.   return TRUE;
  147. }
  148.  
  149. //------------------------------------------------------------------------
  150. // the default cancel routine for an queued Irp
  151. //
  152. void CancelRequest(PDEVICE_OBJECT device_Obj, PIRP Irp)
  153. {
  154.         FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  155.         DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  156.         PCIADA      *pciada   = pDevExt->cc32[file_obj->uwAssociatedCC32];
  157.  
  158.         if (pciada->pBlockingIrp == (PIRP *)NULL)
  159.         {
  160.                 IoReleaseCancelSpinLock(Irp->CancelIrql);
  161.                 KdPrint(("Nothing to do: CancelRequest(0x%08x)\n", Irp));
  162.                 return;
  163.         }
  164.         else
  165.         {
  166.                 // release control of interrupt
  167.                 if (pciada->pIrqControlFile == file_obj)
  168.                 {
  169.                         pciada->pIrqControlFile = (FILE_OBJ *)NULL;
  170.                         globalInterruptDisable(pciada);
  171.                 }
  172.  
  173.                 // cancel any blocking Irp origin from this file
  174.                 if (file_obj->blockingIrp != (PIRP)NULL)
  175.                         file_obj->blockingIrp = (PIRP)NULL;
  176.  
  177.                 if (pciada->pBlockingIrp == &file_obj->blockingIrp)
  178.                         pciada->pBlockingIrp = (PIRP *)NULL;
  179.  
  180.                 IoReleaseCancelSpinLock(Irp->CancelIrql);
  181.  
  182.                 KdPrint(("Done: CancelRequest(0x%08x)\n", Irp));
  183.  
  184.                 Irp->IoStatus.Status = STATUS_CANCELLED;
  185.                 Irp->IoStatus.Information = 0;
  186.  
  187.                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
  188.         }
  189. }
  190.  
  191. //------------------------------------------------------------------------
  192. // the custom deffered routine to finish blocking io on irq_block
  193. void fMyDefferedRoutine(PKDPC Dpc, PVOID pvDevice_object, PVOID pvPciada, PVOID pdwIrqStatus)
  194. {
  195.         NTSTATUS Status = STATUS_SUCCESS;
  196.         ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
  197.     PIRP  Irp = (PIRP)NULL;
  198.         PCIADA          *pciada = (PCIADA *)pvPciada;
  199.         KIRQL                   oldIrqlCancel;
  200.  
  201.         UNREFERENCED_PARAMETER(Dpc);
  202.         UNREFERENCED_PARAMETER(pdwIrqStatus);
  203.         UNREFERENCED_PARAMETER(pvDevice_object);
  204.     KdPrint(("fMyDefferedRoutine(0x%08x)\n", pciada->dwIrqStatus));
  205.  
  206.         // beware off damage due to intercept at cancel of thread
  207.     IoAcquireCancelSpinLock(&oldIrqlCancel);
  208.  
  209.         // get my associated packet
  210.         if (pciada->pBlockingIrp != (PIRP *)NULL)
  211.         {
  212.                 Irp = *pciada->pBlockingIrp;
  213.  
  214.                 if (Irp != (PIRP)NULL) // then a blcoking Irp is waiting
  215.                 {
  216.                         FILE_OBJ *file_obj               = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  217.                         PCICC32_IRQ_RESPONSE *pIrqStatus = (PCICC32_IRQ_RESPONSE *)(Irp->AssociatedIrp.SystemBuffer);
  218.  
  219.                         // fill the response structure
  220.                         pIrqStatus->dwInterruptFlags = pciada->dwIrqStatus;
  221.                         pciada->dwIrqStatus = 0;          // to prevent a following direct return
  222.                         pIrqStatus->dwInterface      = file_obj->uwAssociatedCC32;
  223.  
  224.                         // release the cancel routine from this Irp
  225.                         IoSetCancelRoutine(Irp, NULL);
  226.  
  227.                         COMPLETE_REQUEST;
  228.  
  229.                         file_obj->blockingIrp = (PIRP)NULL;
  230.                 }
  231.  
  232.                 pciada->pBlockingIrp  = (PIRP *)NULL;
  233.         }
  234.  
  235.         // release the spin locks
  236.         IoReleaseCancelSpinLock(oldIrqlCancel);
  237. }
  238.  
  239. //------------------------------------------------------------------------
  240. // if the interrupt is disabled for a blocking path, cancel the block
  241. static void ReleaseBlockingIrp(PDEVICE_OBJECT device_Obj, PCIADA *pciada, PFILE_OBJ pFile_obj)
  242. {
  243.         NTSTATUS Status = STATUS_CANCELLED;
  244.         ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
  245.     PIRP  Irp       = (PIRP)NULL;
  246.         KIRQL oldIrqlCancel;
  247.         UNREFERENCED_PARAMETER(device_Obj);
  248.         UNREFERENCED_PARAMETER(pFile_obj);
  249.  
  250.         UNREFERENCED_PARAMETER(irp_info);
  251.     KdPrint(("ReleaseBlockingIrp()\n"));
  252.  
  253.         // beware off damage due to intercept with cancel of thread
  254.         IoAcquireCancelSpinLock(&oldIrqlCancel);
  255.  
  256.         if (pciada->pBlockingIrp != (PIRP *)NULL)
  257.         {
  258.                 // get my associated packet
  259.                 Irp = *pciada->pBlockingIrp;
  260.  
  261.                 if (Irp != (PIRP)NULL)
  262.                 {
  263.                         FILE_OBJ *file_obj               = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  264.                         PCICC32_IRQ_RESPONSE *pIrqStatus = (PCICC32_IRQ_RESPONSE *)(Irp->AssociatedIrp.SystemBuffer);
  265.                         ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
  266.  
  267.                         pIrqStatus->dwInterruptFlags = pciada->dwIrqStatus;
  268.                         pIrqStatus->dwInterface      = file_obj->uwAssociatedCC32;
  269.  
  270.                         // release the cancel routine from this Irp
  271.                         IoSetCancelRoutine(Irp, NULL);
  272.  
  273.                         COMPLETE_REQUEST;
  274.  
  275.                         file_obj->blockingIrp = (PIRP)NULL;
  276.                 }
  277.  
  278.                 pciada->pBlockingIrp = (PIRP *)NULL; // mark the storage for blocking Irp free
  279.         }
  280.  
  281.         // release the spin locks
  282.         IoReleaseCancelSpinLock(oldIrqlCancel);
  283. }
  284.  
  285. //------------------------------------------------------------------------
  286. // all functions called from ioctl jump table
  287. //
  288.  
  289. //------------------------------------------------------------------------
  290. // a dummy entry because of compatibiltiy (near) WIN95 driver
  291. static NTSTATUS ioctl_dummy(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
  292. {
  293.         NTSTATUS        Status    = STATUS_SUCCESS;
  294.         ULONG           irp_info  = 0;
  295.         PVOID           pInputBuffer,pOutputBuffer;
  296.         ULONG           InputLength, OutputLength;
  297.         char            *pCommand;
  298.  
  299.         FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  300. #ifndef _DEBUG
  301.         UNREFERENCED_PARAMETER(file_obj);
  302. #endif
  303.         SET_BUFFERS_METHOD_BUFFERED;
  304.         UNREFERENCED_PARAMETER(device_Obj);
  305.         pCommand = (char *)pInputBuffer;
  306.  
  307.     KdPrint(("ioctl_dummy(%d)\n", file_obj->uwAssociatedCC32));
  308.  
  309.         // do what must be here in between -----------
  310.        
  311.         // do what must be here in between --- end ---
  312.  
  313.         COMPLETE_REQUEST;
  314.  
  315.     KdPrint(("ioctl_dummy(), Status = 0x%08x\n", Status));
  316.  
  317.         return Status;
  318. }
  319.  
  320. //------------------------------------------------------------------------
  321. // requests status
  322. static NTSTATUS ioctl_get_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
  323. {
  324.         NTSTATUS        Status    = STATUS_SUCCESS;
  325.         ULONG           irp_info  = sizeof(PCICC32_STATUS);
  326.         PVOID           pInputBuffer,pOutputBuffer;
  327.         ULONG           InputLength, OutputLength;
  328.         PCIADA      *pciada;
  329.         DEVICE_EXT      *pDevExt;
  330.         PCICC32_STATUS *pStatus;
  331.         FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  332.         USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
  333.  
  334.         // do what must be here in between -----------
  335.         pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  336.  
  337.         SET_BUFFERS_METHOD_BUFFERED;
  338.  
  339.     KdPrint(("ioctl_get_status(%d)\n", wModuleNumber));
  340.  
  341.         // do what must be here in between -----------
  342.         if (OutputLength >= sizeof(PCICC32_STATUS))
  343.         {
  344.                 USHORT temp;
  345.  
  346.                 pStatus = (PCICC32_STATUS *)pOutputBuffer;
  347.  
  348.                 pciada = pDevExt->cc32[wModuleNumber];
  349.  
  350.                 pStatus->dwInterface    = wModuleNumber;
  351.  
  352.                 temp = READ_REGISTER_USHORT(pciada->pwIntCSR);
  353.                 pStatus->bTimeout                       = (temp & 0x0020) ? 1 : 0;
  354.                 pStatus->bInterrupt                     = (temp & 0x0004) ? 1 : 0;
  355.         }
  356.         else
  357.                 Status = STATUS_BUFFER_TOO_SMALL;
  358.         // do what must be here in between --- end ---
  359.  
  360.         COMPLETE_REQUEST;
  361.  
  362.     KdPrint(("ioctl_get_status(), Status = 0x%08x\n", Status));
  363.  
  364.         return Status;
  365. }
  366.  
  367. //------------------------------------------------------------------------
  368. // clears status
  369. static BOOLEAN ioctl_clear_status_kernel(PVOID pvContext)
  370. {
  371.         PCIADA *pciada = (PCIADA *)pvContext;
  372.         USHORT wCntrl;
  373.  
  374.         // get current Cntrl - and clear interrupt
  375.         wCntrl  = READ_REGISTER_USHORT(pciada->pwCntrl);
  376.         wCntrl &= ~0x0100;  // disable
  377.         WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl);
  378.         wCntrl |= 0x0100;   // enable again
  379.         WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl);
  380.  
  381.         return TRUE;
  382. }
  383.  
  384. static NTSTATUS ioctl_clear_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
  385. {
  386.         NTSTATUS        Status    = STATUS_SUCCESS;
  387.         ULONG           irp_info  = 0;
  388.         PVOID           pInputBuffer,pOutputBuffer;
  389.         ULONG           InputLength, OutputLength;
  390.         PCIADA      *pciada;
  391.         DEVICE_EXT      *pDevExt;
  392.         FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  393.         USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
  394.  
  395.         // do what must be here in between -----------
  396.         pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  397.  
  398.         SET_BUFFERS_METHOD_BUFFERED;
  399.  
  400.     KdPrint(("ioctl_clear_status(%d)\n", wModuleNumber));
  401.  
  402.         // do what must be here in between -----------
  403.         pciada = pDevExt->cc32[wModuleNumber];
  404.  
  405.         KeSynchronizeExecution(pciada->InterruptObject, ioctl_clear_status_kernel, pciada);
  406.  
  407.         // do what must be here in between --- end ---
  408.  
  409.         COMPLETE_REQUEST;
  410.  
  411.     KdPrint(("ioctl_clear_status() OK\n"));
  412.  
  413.         return Status;
  414. }
  415.  
  416. //------------------------------------------------------------------------
  417. // set parameter for this path for future access to CC32
  418. static NTSTATUS ioctl_access_para(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
  419. {
  420.         NTSTATUS        Status    = STATUS_SUCCESS;
  421.         ULONG           irp_info  = 0;
  422.         PVOID           pInputBuffer,pOutputBuffer;
  423.         ULONG           InputLength, OutputLength;
  424.         PCICC32_ACCESS_COMMAND *pAccessPara;
  425.         FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  426.         USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
  427.         DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  428.         PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
  429.         UNREFERENCED_PARAMETER(pciada);
  430.         SET_BUFFERS_METHOD_BUFFERED;
  431.  
  432.     KdPrint(("ioctl_access_para(%d)\n", wModuleNumber));
  433.    
  434.         pAccessPara = (PCICC32_ACCESS_COMMAND *)pInputBuffer;
  435.  
  436.         // do here in between what has to be done -----------------
  437.         file_obj->wAccessType       = pAccessPara->wAccessType;
  438.         file_obj->wBlockTransfer    = pAccessPara->wBlockTransfer;
  439.  
  440.         pAccessPara->dwInterface = wModuleNumber;
  441.  
  442.         switch (pAccessPara->wAccessType)
  443.         {
  444.                 case WORD_ACCESS: file_obj->fRead  = readWord;
  445.                                                   file_obj->fWrite = writeWord;
  446.                                                   break;
  447.                 case LONG_ACCESS: file_obj->fRead  = readLong;
  448.                                                   file_obj->fWrite = writeLong;
  449.                                                   break;
  450.                 default: Status = STATUS_UNSUCCESSFUL;
  451.                                                   break;
  452.         }
  453.         // do here in between what has to be done end -------------
  454.  
  455.         COMPLETE_REQUEST;
  456.  
  457.     KdPrint(("ioctl_access_para(), Status = 0x%08x\n", Status));
  458.  
  459.         return Status;
  460. }
  461.  
  462. //------------------------------------------------------------------------
  463. // allow or inhibit interrupt requests from either CC32 or thru local timeout
  464. static NTSTATUS ioctl_control_interrupts(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
  465. {
  466.         NTSTATUS        Status    = STATUS_SUCCESS;
  467.         ULONG           irp_info  = 0;
  468.         PVOID           pInputBuffer,pOutputBuffer;
  469.         ULONG           InputLength, OutputLength;
  470.         PCICC32_IRQ_CONTROL *pIrqControlIn, *pIrqControlOut;
  471.         FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  472.         USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
  473.         DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  474.         PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
  475.  
  476.         SET_BUFFERS_METHOD_BUFFERED;
  477.  
  478.     KdPrint(("ioctl_control_interrupts(%d)\n", wModuleNumber));
  479.    
  480.         pIrqControlIn  = (PCICC32_IRQ_CONTROL *)pInputBuffer;
  481.         pIrqControlOut = (PCICC32_IRQ_CONTROL *)pOutputBuffer;
  482.  
  483.         // do here in between what has to be done -----------------
  484.         if (pIrqControlIn->wEnable)
  485.         {
  486.                 // reserve the controlling of interrupts for this path
  487.                 if ((pciada->pIrqControlFile == (FILE_OBJ *)NULL) ||
  488.                         (pciada->pIrqControlFile == file_obj))
  489.                 {
  490.                         pciada->pIrqControlFile = file_obj;
  491.                         globalInterruptEnable(pciada);
  492.                 }
  493.                 else
  494.                         Status = STATUS_DEVICE_BUSY;
  495.         }
  496.         else
  497.         {
  498.                 // nobody else is allowed to disable interrupts
  499.                 if (pciada->pIrqControlFile == file_obj)
  500.                 {
  501.                         pciada->pIrqControlFile = (FILE_OBJ *)NULL;
  502.                         globalInterruptDisable(pciada);
  503.                 }
  504.                 else
  505.                         Status = STATUS_DEVICE_BUSY;
  506.         }
  507.  
  508.         // give back if the user grants space
  509.         if (OutputLength >= sizeof(PCICC32_IRQ_CONTROL))
  510.         {
  511.                 pIrqControlOut->dwInterface = wModuleNumber;
  512.                 pIrqControlOut->wEnable     = globalInterruptEnabledStatus(pciada);
  513.         }      
  514.         // do here in between what has to be done end -------------
  515.  
  516.         COMPLETE_REQUEST;
  517.  
  518.     KdPrint(("ioctl_control_interrupts(), Status = 0x%08x\n", Status));
  519.  
  520.         return Status;
  521. }
  522.  
  523. //------------------------------------------------------------------------
  524. // implements a blocking io-call to get irq status.
  525. static BOOLEAN ioctl_irq_status_kernel(PVOID pvContext)
  526. {
  527.         IOCTL_IRQ_STATUS_CONTEXT *context = (IOCTL_IRQ_STATUS_CONTEXT *)pvContext;
  528.     KIRQL       oldIrql;
  529.  
  530.         if (context->pciada->dwIrqStatus)
  531.         {
  532.                 // there is a pending interrupt - return immediately
  533.                 KdPrint(("ioctl_irq_status(), direct return (0x%08x)\n", context->pciada->dwIrqStatus));
  534.  
  535.                 context->pIrqStatus->dwInterruptFlags = context->pciada->dwIrqStatus;
  536.                 context->pciada->dwIrqStatus          = 0;  // release pending status
  537.  
  538.                 *context->irp_info = sizeof(PCICC32_IRQ_RESPONSE);
  539.         }
  540.         else
  541.         {
  542.                 // make the request blocking
  543.                 IoAcquireCancelSpinLock(&oldIrql);
  544.  
  545.                 if ((*context->Irp)->Cancel)    // cancel while doing
  546.                 {
  547.                         KdPrint(("ioctl_irq_status(), canceled return\n"));
  548.                         *context->Status = STATUS_CANCELLED;
  549.                 }
  550.                 else
  551.                 {
  552.                         KdPrint(("ioctl_irq_status(), blocking\n"));
  553.  
  554.                         if (context->pciada->pBlockingIrp != (PIRP *)NULL)
  555.                         {
  556.                                 // a Irp is still waiting
  557.                                 *context->Status = STATUS_DEVICE_BUSY;
  558.                         }
  559.                         else
  560.                         {
  561.                                 context->file_obj->blockingIrp = *context->Irp;
  562.                                 context->pciada->pBlockingIrp  = &context->file_obj->blockingIrp;
  563.  
  564.                                 *context->Status = STATUS_PENDING;
  565.  
  566.                                 // mark irp as pending and return
  567.                                 IoMarkIrpPending(*context->Irp);
  568.                                 IoSetCancelRoutine(*context->Irp, CancelRequest);
  569.                         }
  570.                 } // if (Irp->Cancel) ...
  571.         }
  572.  
  573.         return TRUE;
  574. }
  575.  
  576. static NTSTATUS ioctl_irq_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
  577. {
  578.         NTSTATUS        Status    = STATUS_SUCCESS;
  579.         ULONG           irp_info  = 0;
  580.         PVOID           pInputBuffer,pOutputBuffer;
  581.         ULONG           InputLength, OutputLength;
  582.         DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  583.         USHORT      wModuleNumber;
  584.         IOCTL_IRQ_STATUS_CONTEXT context;
  585.  
  586.         SET_BUFFERS_METHOD_BUFFERED;
  587.  
  588.         context.file_obj   = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  589.         wModuleNumber      = context.file_obj->uwAssociatedCC32;
  590.         context.pciada     = pDevExt->cc32[wModuleNumber];
  591.         context.pIrqStatus = (PCICC32_IRQ_RESPONSE *)pOutputBuffer;
  592.         context.Status     = &Status;
  593.         context.irp_info   = &irp_info;
  594.         context.Irp        = &Irp;
  595.  
  596.  
  597.     KdPrint(("ioctl_irq_status(%d)\n", wModuleNumber));
  598.    
  599.         // do here in between what has to be done -----------------
  600.         if (OutputLength < sizeof(PCICC32_IRQ_RESPONSE))
  601.                 Status = STATUS_BUFFER_TOO_SMALL;
  602.         else
  603.         {
  604.                 context.pIrqStatus->dwInterface = wModuleNumber;
  605.  
  606.             KeSynchronizeExecution(context.pciada->InterruptObject, ioctl_irq_status_kernel, &context);
  607.         }
  608.         // do here in between what has to be done end -------------
  609.  
  610.         COMPLETE_REQUEST;
  611.  
  612.     KdPrint(("ioctl_irq_status(), Status = 0x%08x\n", Status));
  613.  
  614.         return Status;
  615. }
  616.  
  617.  
  618. //------------------------------------------------------------------------
  619. // for test and debug purposes: direkt access to PLX LCR space
  620. static NTSTATUS ioctl_access_lcr(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
  621. {
  622.         NTSTATUS        Status    = STATUS_SUCCESS;
  623.         ULONG           irp_info  = 0;
  624.         PVOID           pInputBuffer,pOutputBuffer;
  625.         ULONG           InputLength, OutputLength;
  626.         FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
  627.         USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
  628.         DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
  629.         PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
  630.         PCICC32_LCR_ACCESS *pAccessOut;
  631.         PCICC32_LCR_ACCESS *pAccessIn;
  632.  
  633.         SET_BUFFERS_METHOD_BUFFERED;
  634.  
  635.     KdPrint(("ioctl_access_lcr(%d)\n", wModuleNumber));
  636.    
  637.         pAccessOut = (PCICC32_LCR_ACCESS *)pOutputBuffer;
  638.         pAccessIn  = (PCICC32_LCR_ACCESS *)pInputBuffer;
  639.  
  640.         // do here in between what has to be done -----------------
  641.         if (OutputLength < sizeof(PCICC32_LCR_ACCESS))
  642.                 Status = STATUS_BUFFER_TOO_SMALL;
  643.         else
  644.         {
  645.                 *pAccessOut = *pAccessIn;
  646.                 pAccessOut->dwInterface = wModuleNumber;
  647.  
  648.                 if (pAccessIn->wRegisterAddress <= 0x52)
  649.                 {
  650.                         // 1st part: long word accesses
  651.                         if (pAccessIn->bBytesLane == LONG_ACCESS)
  652.                         {
  653.                                 if (pAccessIn->wRegisterAddress & 0x0003)
  654.                                         Status = STATUS_INSTRUCTION_MISALIGNMENT;
  655.                                 else
  656.                                 {
  657.                                         ULONG       *pdwVirtAddress;
  658.                                         ULONG           dwDummy;
  659.  
  660.                                         pdwVirtAddress = (ULONG *)((ULONG)pciada->pvVirtLcr + pAccessIn->wRegisterAddress);
  661.  
  662.                                         switch (pAccessIn->bAccessMode)
  663.                                         {
  664.                                                 case LCR_WRITE:
  665.                                                         WRITE_REGISTER_ULONG(pdwVirtAddress, pAccessIn->dwContent);
  666.                                                         pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
  667.                                                         break;
  668.                                                 case LCR_OR:
  669.                                                         dwDummy  = READ_REGISTER_ULONG(pdwVirtAddress);
  670.                                                         dwDummy |= pAccessIn->dwContent;
  671.                                                         WRITE_REGISTER_ULONG(pdwVirtAddress, dwDummy);
  672.                                                         pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
  673.                                                         break;
  674.                                                 case LCR_AND:
  675.                                                         dwDummy  = READ_REGISTER_ULONG(pdwVirtAddress);
  676.                                                         dwDummy &= pAccessIn->dwContent;
  677.                                                         WRITE_REGISTER_ULONG(pdwVirtAddress, dwDummy);
  678.                                                         pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
  679.                                                         break;
  680.                                                 case LCR_WRITE_ONLY:
  681.                                                         WRITE_REGISTER_ULONG(pdwVirtAddress, pAccessIn->dwContent);
  682.                                                         break;
  683.                                                 case LCR_READ:
  684.                                                         pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
  685.                                                         break;
  686.  
  687.                                                 default: Status = STATUS_ILLEGAL_INSTRUCTION;
  688.                                         }
  689.                                 }
  690.                         }
  691.  
  692.                         // 2nd part: short word accesses
  693.                         if (pAccessIn->bBytesLane == WORD_ACCESS)
  694.                         {
  695.                                 if (pAccessIn->wRegisterAddress & 0x0001)
  696.                                         Status = STATUS_INSTRUCTION_MISALIGNMENT;
  697.                                 else
  698.                                 {
  699.                                         USHORT      *pwVirtAddress;
  700.                                         USHORT          wDummy;
  701.  
  702.                                         pwVirtAddress = (USHORT *)((ULONG)pciada->pvVirtLcr + pAccessIn->wRegisterAddress);
  703.  
  704.                                         switch (pAccessIn->bAccessMode)
  705.                                         {
  706.                                                 case LCR_WRITE:
  707.                                                         WRITE_REGISTER_USHORT(pwVirtAddress, (USHORT)pAccessIn->dwContent);
  708.                                                         pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
  709.                                                         break;
  710.                                                 case LCR_OR:
  711.                                                         wDummy  = READ_REGISTER_USHORT(pwVirtAddress);
  712.                                                         wDummy |= (USHORT)pAccessIn->dwContent;
  713.                                                         WRITE_REGISTER_USHORT(pwVirtAddress, wDummy);
  714.                                                         pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
  715.                                                         break;
  716.                                                 case LCR_AND:
  717.                                                         wDummy  = READ_REGISTER_USHORT(pwVirtAddress);
  718.                                                         wDummy &= (USHORT)pAccessIn->dwContent;
  719.                                                         WRITE_REGISTER_USHORT(pwVirtAddress, wDummy);
  720.                                                         pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
  721.                                                         break;
  722.                                                 case LCR_WRITE_ONLY:
  723.                                                         WRITE_REGISTER_USHORT(pwVirtAddress, (USHORT)pAccessIn->dwContent);
  724.                                                         break;
  725.                                                 case LCR_READ:
  726.                                                         pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
  727.                                                         break;
  728.  
  729.                                                 default: Status = STATUS_ILLEGAL_INSTRUCTION;
  730.                                                         break;
  731.                                         }
  732.                                 }
  733.                         }
  734.  
  735.                         // 3rd part: check illegal byte lanes
  736.                         if (!((pAccessIn->bBytesLane == LONG_ACCESS) || (pAccessIn->bBytesLane == WORD_ACCESS)))
  737.                                 Status = STATUS_ILLEGAL_INSTRUCTION;
  738.                 }
  739.                 else
  740.                         Status = STATUS_ILLEGAL_INSTRUCTION;
  741.         }      
  742.         // do here in between what has to be done end -------------
  743.  
  744.         if (Status == STATUS_SUCCESS)          
  745.                 irp_info = sizeof(PCICC32_LCR_ACCESS);
  746.  
  747.         COMPLETE_REQUEST;
  748.  
  749.     KdPrint(("ioctl_access_lcr(), Status = 0x%08x\n", Status));
  750.  
  751.         return Status;
  752. }
  753.  
  754.  
  755. //------------------------------------------------------------------------
  756. // the ultimate jumptable for ioctl
  757. //
  758. NTSTATUS (*ioctl[])(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack) =  
  759. {
  760.         ioctl_dummy,                                    // 0
  761.         ioctl_dummy,                                    // 4
  762.         ioctl_get_status,                               // 8
  763.         ioctl_clear_status,                             // 0x0c
  764.         ioctl_access_para,                              // 0x10
  765.         ioctl_control_interrupts,       // 0x14
  766.         ioctl_dummy,                    // 0x18
  767.         ioctl_irq_status,               // 0x1c
  768.         ioctl_access_lcr                // 0x20
  769. };
  770.  
  771.