Subversion Repositories f9daq

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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