//-------------------------------------------------------------------------
 
// WINNT driver for PCICC32 interface from ARW Elektronik, Germany ---------
 
// the ioctl functions
 
//
 
// (c) 1999-2002 ARW Elektronik
 
//
 
// this source code is published under GPL (Open Source). You can use, redistrubute and 
 
// modify it unless this header   is not modified or deleted. No warranty is given that 
 
// this software will work like expected.
 
// This product is not authorized for use as critical component in life support systems
 
// wihout the express written approval of ARW Elektronik Germany.
 
//
 
// Please announce changes and hints to ARW Elektronik
 
//
 
// what                                            who          when
 
// started                                         AR           03.07.1999
 
// first release 1.0                                                       AR                   17.10.1999
 
// added access to PLX LC-Register                 AR           30.03.2001
 
// changed making procedure (only VCC > 6.0)       AR           30.05.2002
 
// multiple interrupt enable allowed               AR           01.06.2002
 
// added KeSynchronizeExecution for interrupt sync AR           16.06.2002
 
// extended ioctl_irq_status_kernel                AR           18.06.2002
 
//
 
 
 
//-------------------------------------------------------------------------
 
// INCLUDES
 
//
 
#include <ntddk.h>
 
#include <devioctl.h>
 
#include <pcicc32_drv.h>
 
#include <pcicc32.h>
 
#include <pcicc32_v.h>
 
#include <pcicc32_io.h>
 
#include <pcicc32_local.h>
 
#include <pcicc32_i.h>
 
 
 
//------------------------------------------------------------------------
 
// DEFINES
 
//
 
 
 
// buffers usage must match the corresponding ioctl code!
 
#define SET_BUFFERS_METHOD_OUT_DIRECT \
 
{\
 
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
 
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
 
        pInputBuffer  = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
 
        pOutputBuffer = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
 
}
 
 
 
#define SET_BUFFERS_METHOD_IN_DIRECT \
 
{\
 
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
 
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
 
        pInputBuffer  = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));\
 
        pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
 
}
 
 
 
#define SET_BUFFERS_METHOD_BUFFERED \
 
{\
 
        InputLength   = IrpStack->Parameters.DeviceIoControl.InputBufferLength;\
 
        OutputLength  = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;\
 
        pInputBuffer  = pOutputBuffer = ((void *)(Irp->AssociatedIrp.SystemBuffer));\
 
}
 
 
 
#define COMPLETE_REQUEST \
 
{\
 
        if (Status != STATUS_PENDING)\
 
        {\
 
                Irp->IoStatus.Status      = Status; \
 
                Irp->IoStatus.Information = irp_info; \
 
                IoCompleteRequest(Irp,IO_NO_INCREMENT); \
 
        }\
 
}
 
 
 
// compatibilty issues to WIN95 driver calls
 
#ifndef WORD
 
#define WORD USHORT
 
#endif
 
 
 
#ifndef DWORD
 
#define DWORD ULONG
 
#endif
 
 
 
#ifndef BYTE
 
#define BYTE UCHAR
 
#endif
 
 
 
#ifndef BOOL
 
#define BOOL BOOLEAN
 
#endif
 
 
 
 
 
//-------------------------------------------------------------------------
 
// TYPEDEFS
 
//
 
typedef struct
 
{
 
        FILE_OBJ    *file_obj;
 
        PCIADA      *pciada;
 
        PCICC32_IRQ_RESPONSE *pIrqStatus;
 
        PIRP        *Irp;
 
        ULONG       *irp_info;
 
        NTSTATUS    *Status;
 
} IOCTL_IRQ_STATUS_CONTEXT;
 
 
 
//--------------------------------------------------------------------------
 
// LOCAL FUNCTIONS
 
//
 
 
 
//--------------------------------------------------------------------------
 
// fast read or write functions - portable -
 
static void readWord(void *to, void *from)
 
{
 
        *(PUSHORT)to = READ_REGISTER_USHORT((PUSHORT)from);
 
}
 
 
 
static void readLong(void *to, void *from) 
 
{
 
        *(PULONG)to = READ_REGISTER_ULONG((PULONG)from);
 
}
 
 
 
static void writeWord(void *to, void *from)
 
{
 
        WRITE_REGISTER_USHORT((PUSHORT)to, *(PUSHORT)from);
 
}
 
 
 
static void writeLong(void *to, void *from)
 
{
 
        WRITE_REGISTER_ULONG((PULONG)to, *(PULONG)from);
 
}
 
 
 
//------------------------------------------------------------------------
 
// init the interface with build in and user supplied constants
 
static BOOLEAN InitInterface(PVOID pvLcr, PVOID pvIfr)
 
{
 
  UNREFERENCED_PARAMETER(pvLcr);
 
  UNREFERENCED_PARAMETER(pvIfr);
 
  return TRUE;
 
}
 
 
 
// deinit the interface with user supplied and build in constants
 
static BOOLEAN DeInitInterface(PVOID pvLcr, PVOID pvIfr)
 
{
 
  UNREFERENCED_PARAMETER(pvLcr);
 
  UNREFERENCED_PARAMETER(pvIfr);
 
  return TRUE;
 
}
 
 
 
//------------------------------------------------------------------------
 
// the default cancel routine for an queued Irp 
 
//
 
void CancelRequest(PDEVICE_OBJECT device_Obj, PIRP Irp)
 
{
 
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
        PCIADA      *pciada   = pDevExt->cc32[file_obj->uwAssociatedCC32];
 
 
 
        if (pciada->pBlockingIrp == (PIRP *)NULL)
 
        {
 
                IoReleaseCancelSpinLock(Irp->CancelIrql); 
 
                KdPrint(("Nothing to do: CancelRequest(0x%08x)\n", Irp));
 
                return;
 
        }
 
        else
 
        { 
 
                // release control of interrupt
 
                if (pciada->pIrqControlFile == file_obj)
 
                {
 
                        pciada->pIrqControlFile = (FILE_OBJ *)NULL;
 
                        globalInterruptDisable(pciada);
 
                }
 
 
 
                // cancel any blocking Irp origin from this file
 
                if (file_obj->blockingIrp != (PIRP)NULL)
 
                        file_obj->blockingIrp = (PIRP)NULL;
 
 
 
                if (pciada->pBlockingIrp == &file_obj->blockingIrp)
 
                        pciada->pBlockingIrp = (PIRP *)NULL;
 
 
 
                IoReleaseCancelSpinLock(Irp->CancelIrql); 
 
 
 
                KdPrint(("Done: CancelRequest(0x%08x)\n", Irp));
 
 
 
                Irp->IoStatus.Status = STATUS_CANCELLED; 
 
                Irp->IoStatus.Information = 0; 
 
 
 
                IoCompleteRequest(Irp, IO_NO_INCREMENT); 
 
        }
 
}
 
 
 
//------------------------------------------------------------------------
 
// the custom deffered routine to finish blocking io on irq_block
 
void fMyDefferedRoutine(PKDPC Dpc, PVOID pvDevice_object, PVOID pvPciada, PVOID pdwIrqStatus)
 
{
 
        NTSTATUS Status = STATUS_SUCCESS;
 
        ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
 
    PIRP  Irp = (PIRP)NULL; 
 
        PCIADA          *pciada = (PCIADA *)pvPciada;
 
        KIRQL                   oldIrqlCancel; 
 
 
 
        UNREFERENCED_PARAMETER(Dpc);
 
        UNREFERENCED_PARAMETER(pdwIrqStatus);
 
        UNREFERENCED_PARAMETER(pvDevice_object);
 
    KdPrint(("fMyDefferedRoutine(0x%08x)\n", pciada->dwIrqStatus));
 
 
 
        // beware off damage due to intercept at cancel of thread
 
    IoAcquireCancelSpinLock(&oldIrqlCancel); 
 
 
 
        // get my associated packet
 
        if (pciada->pBlockingIrp != (PIRP *)NULL)
 
        {
 
                Irp = *pciada->pBlockingIrp;
 
 
 
                if (Irp != (PIRP)NULL) // then a blcoking Irp is waiting
 
                {
 
                        FILE_OBJ *file_obj               = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
                        PCICC32_IRQ_RESPONSE *pIrqStatus = (PCICC32_IRQ_RESPONSE *)(Irp->AssociatedIrp.SystemBuffer);
 
 
 
                        // fill the response structure
 
                        pIrqStatus->dwInterruptFlags = pciada->dwIrqStatus; 
 
                        pciada->dwIrqStatus = 0;          // to prevent a following direct return
 
                        pIrqStatus->dwInterface      = file_obj->uwAssociatedCC32;
 
 
 
                        // release the cancel routine from this Irp
 
                        IoSetCancelRoutine(Irp, NULL); 
 
 
 
                        COMPLETE_REQUEST;
 
 
 
                        file_obj->blockingIrp = (PIRP)NULL;
 
                }
 
 
 
                pciada->pBlockingIrp  = (PIRP *)NULL;
 
        }
 
 
 
        // release the spin locks
 
        IoReleaseCancelSpinLock(oldIrqlCancel); 
 
}
 
 
 
//------------------------------------------------------------------------
 
// if the interrupt is disabled for a blocking path, cancel the block 
 
static void ReleaseBlockingIrp(PDEVICE_OBJECT device_Obj, PCIADA *pciada, PFILE_OBJ pFile_obj)
 
{
 
        NTSTATUS Status = STATUS_CANCELLED;
 
        ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
 
    PIRP  Irp       = (PIRP)NULL; 
 
        KIRQL oldIrqlCancel; 
 
        UNREFERENCED_PARAMETER(device_Obj);
 
        UNREFERENCED_PARAMETER(pFile_obj);
 
 
 
        UNREFERENCED_PARAMETER(irp_info);
 
    KdPrint(("ReleaseBlockingIrp()\n"));
 
 
 
        // beware off damage due to intercept with cancel of thread
 
        IoAcquireCancelSpinLock(&oldIrqlCancel); 
 
 
 
        if (pciada->pBlockingIrp != (PIRP *)NULL)
 
        {
 
                // get my associated packet
 
                Irp = *pciada->pBlockingIrp;
 
 
 
                if (Irp != (PIRP)NULL)
 
                {
 
                        FILE_OBJ *file_obj               = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
                        PCICC32_IRQ_RESPONSE *pIrqStatus = (PCICC32_IRQ_RESPONSE *)(Irp->AssociatedIrp.SystemBuffer);
 
                        ULONG irp_info  = sizeof(PCICC32_IRQ_RESPONSE);
 
 
 
                        pIrqStatus->dwInterruptFlags = pciada->dwIrqStatus;
 
                        pIrqStatus->dwInterface      = file_obj->uwAssociatedCC32;
 
 
 
                        // release the cancel routine from this Irp
 
                        IoSetCancelRoutine(Irp, NULL); 
 
 
 
                        COMPLETE_REQUEST;
 
 
 
                        file_obj->blockingIrp = (PIRP)NULL;
 
                }
 
 
 
                pciada->pBlockingIrp = (PIRP *)NULL; // mark the storage for blocking Irp free
 
        }
 
 
 
        // release the spin locks
 
        IoReleaseCancelSpinLock(oldIrqlCancel); 
 
}
 
 
 
//------------------------------------------------------------------------
 
// all functions called from ioctl jump table
 
//
 
 
 
//------------------------------------------------------------------------
 
// a dummy entry because of compatibiltiy (near) WIN95 driver
 
static NTSTATUS ioctl_dummy(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
 
{
 
        NTSTATUS        Status    = STATUS_SUCCESS;
 
        ULONG           irp_info  = 0;
 
        PVOID           pInputBuffer,pOutputBuffer;
 
        ULONG           InputLength, OutputLength;
 
        char            *pCommand;
 
 
 
        FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
#ifndef _DEBUG
 
        UNREFERENCED_PARAMETER(file_obj);
 
#endif
 
        SET_BUFFERS_METHOD_BUFFERED;
 
        UNREFERENCED_PARAMETER(device_Obj);
 
        pCommand = (char *)pInputBuffer;
 
 
 
    KdPrint(("ioctl_dummy(%d)\n", file_obj->uwAssociatedCC32));
 
 
 
        // do what must be here in between -----------
 
        
 
        // do what must be here in between --- end ---
 
 
 
        COMPLETE_REQUEST;
 
 
 
    KdPrint(("ioctl_dummy(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
//------------------------------------------------------------------------
 
// requests status
 
static NTSTATUS ioctl_get_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
 
{
 
        NTSTATUS        Status    = STATUS_SUCCESS;
 
        ULONG           irp_info  = sizeof(PCICC32_STATUS);
 
        PVOID           pInputBuffer,pOutputBuffer;
 
        ULONG           InputLength, OutputLength;
 
        PCIADA      *pciada;
 
        DEVICE_EXT      *pDevExt;
 
        PCICC32_STATUS *pStatus;
 
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
 
 
 
        // do what must be here in between -----------
 
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
 
 
        SET_BUFFERS_METHOD_BUFFERED;
 
 
 
    KdPrint(("ioctl_get_status(%d)\n", wModuleNumber));
 
 
 
        // do what must be here in between -----------
 
        if (OutputLength >= sizeof(PCICC32_STATUS))
 
        {
 
                USHORT temp;
 
 
 
                pStatus = (PCICC32_STATUS *)pOutputBuffer;
 
 
 
                pciada = pDevExt->cc32[wModuleNumber]; 
 
 
 
                pStatus->dwInterface    = wModuleNumber;
 
 
 
                temp = READ_REGISTER_USHORT(pciada->pwIntCSR);
 
                pStatus->bTimeout                       = (temp & 0x0020) ? 1 : 0;
 
                pStatus->bInterrupt                     = (temp & 0x0004) ? 1 : 0;
 
        }
 
        else
 
                Status = STATUS_BUFFER_TOO_SMALL;
 
        // do what must be here in between --- end ---
 
 
 
        COMPLETE_REQUEST;
 
 
 
    KdPrint(("ioctl_get_status(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
//------------------------------------------------------------------------
 
// clears status
 
static BOOLEAN ioctl_clear_status_kernel(PVOID pvContext)
 
{
 
        PCIADA *pciada = (PCIADA *)pvContext;
 
        USHORT wCntrl;
 
 
 
        // get current Cntrl - and clear interrupt
 
        wCntrl  = READ_REGISTER_USHORT(pciada->pwCntrl);
 
        wCntrl &= ~0x0100;  // disable
 
        WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl); 
 
        wCntrl |= 0x0100;   // enable again
 
        WRITE_REGISTER_USHORT(pciada->pwCntrl, wCntrl);
 
 
 
        return TRUE;
 
}
 
 
 
static NTSTATUS ioctl_clear_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
 
{
 
        NTSTATUS        Status    = STATUS_SUCCESS;
 
        ULONG           irp_info  = 0;
 
        PVOID           pInputBuffer,pOutputBuffer;
 
        ULONG           InputLength, OutputLength;
 
        PCIADA      *pciada;
 
        DEVICE_EXT      *pDevExt;
 
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
 
 
 
        // do what must be here in between -----------
 
        pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
 
 
        SET_BUFFERS_METHOD_BUFFERED;
 
 
 
    KdPrint(("ioctl_clear_status(%d)\n", wModuleNumber));
 
 
 
        // do what must be here in between -----------
 
        pciada = pDevExt->cc32[wModuleNumber]; 
 
 
 
        KeSynchronizeExecution(pciada->InterruptObject, ioctl_clear_status_kernel, pciada);
 
 
 
        // do what must be here in between --- end ---
 
 
 
        COMPLETE_REQUEST;
 
 
 
    KdPrint(("ioctl_clear_status() OK\n"));
 
 
 
        return Status;
 
}
 
 
 
//------------------------------------------------------------------------
 
// set parameter for this path for future access to CC32
 
static NTSTATUS ioctl_access_para(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
 
{
 
        NTSTATUS        Status    = STATUS_SUCCESS;
 
        ULONG           irp_info  = 0;
 
        PVOID           pInputBuffer,pOutputBuffer;
 
        ULONG           InputLength, OutputLength;
 
        PCICC32_ACCESS_COMMAND *pAccessPara;
 
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
 
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
        PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
 
        UNREFERENCED_PARAMETER(pciada);
 
        SET_BUFFERS_METHOD_BUFFERED;
 
 
 
    KdPrint(("ioctl_access_para(%d)\n", wModuleNumber));
 
   
 
        pAccessPara = (PCICC32_ACCESS_COMMAND *)pInputBuffer;
 
 
 
        // do here in between what has to be done -----------------
 
        file_obj->wAccessType       = pAccessPara->wAccessType; 
 
        file_obj->wBlockTransfer    = pAccessPara->wBlockTransfer; 
 
 
 
        pAccessPara->dwInterface = wModuleNumber;
 
 
 
        switch (pAccessPara->wAccessType)
 
        {
 
                case WORD_ACCESS: file_obj->fRead  = readWord; 
 
                                                  file_obj->fWrite = writeWord; 
 
                                                  break;
 
                case LONG_ACCESS: file_obj->fRead  = readLong; 
 
                                                  file_obj->fWrite = writeLong; 
 
                                                  break;
 
                default: Status = STATUS_UNSUCCESSFUL; 
 
                                                  break;
 
        }
 
        // do here in between what has to be done end -------------
 
 
 
        COMPLETE_REQUEST;
 
 
 
    KdPrint(("ioctl_access_para(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
//------------------------------------------------------------------------
 
// allow or inhibit interrupt requests from either CC32 or thru local timeout
 
static NTSTATUS ioctl_control_interrupts(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
 
{
 
        NTSTATUS        Status    = STATUS_SUCCESS;
 
        ULONG           irp_info  = 0;
 
        PVOID           pInputBuffer,pOutputBuffer;
 
        ULONG           InputLength, OutputLength;
 
        PCICC32_IRQ_CONTROL *pIrqControlIn, *pIrqControlOut;
 
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
 
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
        PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
 
 
 
        SET_BUFFERS_METHOD_BUFFERED;
 
 
 
    KdPrint(("ioctl_control_interrupts(%d)\n", wModuleNumber));
 
   
 
        pIrqControlIn  = (PCICC32_IRQ_CONTROL *)pInputBuffer;
 
        pIrqControlOut = (PCICC32_IRQ_CONTROL *)pOutputBuffer;
 
 
 
        // do here in between what has to be done -----------------
 
        if (pIrqControlIn->wEnable)
 
        {
 
                // reserve the controlling of interrupts for this path
 
                if ((pciada->pIrqControlFile == (FILE_OBJ *)NULL) ||
 
                        (pciada->pIrqControlFile == file_obj))
 
                {
 
                        pciada->pIrqControlFile = file_obj;
 
                        globalInterruptEnable(pciada); 
 
                }
 
                else
 
                        Status = STATUS_DEVICE_BUSY;
 
        }
 
        else
 
        {
 
                // nobody else is allowed to disable interrupts
 
                if (pciada->pIrqControlFile == file_obj)
 
                {
 
                        pciada->pIrqControlFile = (FILE_OBJ *)NULL;
 
                        globalInterruptDisable(pciada);
 
                }
 
                else
 
                        Status = STATUS_DEVICE_BUSY;
 
        }
 
 
 
        // give back if the user grants space
 
        if (OutputLength >= sizeof(PCICC32_IRQ_CONTROL))
 
        {
 
                pIrqControlOut->dwInterface = wModuleNumber;
 
                pIrqControlOut->wEnable     = globalInterruptEnabledStatus(pciada);
 
        }       
 
        // do here in between what has to be done end -------------
 
 
 
        COMPLETE_REQUEST;
 
 
 
    KdPrint(("ioctl_control_interrupts(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
//------------------------------------------------------------------------
 
// implements a blocking io-call to get irq status.
 
static BOOLEAN ioctl_irq_status_kernel(PVOID pvContext)
 
{
 
        IOCTL_IRQ_STATUS_CONTEXT *context = (IOCTL_IRQ_STATUS_CONTEXT *)pvContext;
 
    KIRQL       oldIrql; 
 
 
 
        if (context->pciada->dwIrqStatus)
 
        {
 
                // there is a pending interrupt - return immediately
 
                KdPrint(("ioctl_irq_status(), direct return (0x%08x)\n", context->pciada->dwIrqStatus));
 
 
 
                context->pIrqStatus->dwInterruptFlags = context->pciada->dwIrqStatus;
 
                context->pciada->dwIrqStatus          = 0;  // release pending status
 
 
 
                *context->irp_info = sizeof(PCICC32_IRQ_RESPONSE);
 
        }
 
        else
 
        {
 
                // make the request blocking
 
                IoAcquireCancelSpinLock(&oldIrql); 
 
 
 
                if ((*context->Irp)->Cancel)    // cancel while doing
 
                {
 
                        KdPrint(("ioctl_irq_status(), canceled return\n"));
 
                        *context->Status = STATUS_CANCELLED; 
 
                }
 
                else
 
                {
 
                        KdPrint(("ioctl_irq_status(), blocking\n"));
 
 
 
                        if (context->pciada->pBlockingIrp != (PIRP *)NULL) 
 
                        {
 
                                // a Irp is still waiting
 
                                *context->Status = STATUS_DEVICE_BUSY;
 
                        }
 
                        else
 
                        {
 
                                context->file_obj->blockingIrp = *context->Irp;
 
                                context->pciada->pBlockingIrp  = &context->file_obj->blockingIrp;
 
 
 
                                *context->Status = STATUS_PENDING;
 
 
 
                                // mark irp as pending and return
 
                                IoMarkIrpPending(*context->Irp);
 
                                IoSetCancelRoutine(*context->Irp, CancelRequest); 
 
                        }
 
                } // if (Irp->Cancel) ...
 
        }
 
 
 
        return TRUE;
 
}
 
 
 
static NTSTATUS ioctl_irq_status(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
 
{
 
        NTSTATUS        Status    = STATUS_SUCCESS;
 
        ULONG           irp_info  = 0;
 
        PVOID           pInputBuffer,pOutputBuffer;
 
        ULONG           InputLength, OutputLength;
 
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
        USHORT      wModuleNumber;
 
        IOCTL_IRQ_STATUS_CONTEXT context;
 
 
 
        SET_BUFFERS_METHOD_BUFFERED;
 
 
 
        context.file_obj   = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        wModuleNumber      = context.file_obj->uwAssociatedCC32;
 
        context.pciada     = pDevExt->cc32[wModuleNumber];
 
        context.pIrqStatus = (PCICC32_IRQ_RESPONSE *)pOutputBuffer;
 
        context.Status     = &Status;
 
        context.irp_info   = &irp_info;
 
        context.Irp        = &Irp;
 
 
 
 
 
    KdPrint(("ioctl_irq_status(%d)\n", wModuleNumber));
 
   
 
        // do here in between what has to be done -----------------
 
        if (OutputLength < sizeof(PCICC32_IRQ_RESPONSE))
 
                Status = STATUS_BUFFER_TOO_SMALL;
 
        else
 
        {
 
                context.pIrqStatus->dwInterface = wModuleNumber;
 
 
 
            KeSynchronizeExecution(context.pciada->InterruptObject, ioctl_irq_status_kernel, &context);
 
        }
 
        // do here in between what has to be done end -------------
 
 
 
        COMPLETE_REQUEST;
 
 
 
    KdPrint(("ioctl_irq_status(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// for test and debug purposes: direkt access to PLX LCR space
 
static NTSTATUS ioctl_access_lcr(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack)
 
{
 
        NTSTATUS        Status    = STATUS_SUCCESS;
 
        ULONG           irp_info  = 0;
 
        PVOID           pInputBuffer,pOutputBuffer;
 
        ULONG           InputLength, OutputLength;
 
        FILE_OBJ    *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
 
        USHORT      wModuleNumber = file_obj->uwAssociatedCC32;
 
        DEVICE_EXT      *pDevExt  = (DEVICE_EXT *)(device_Obj->DeviceExtension);
 
        PCIADA      *pciada   = pDevExt->cc32[wModuleNumber];
 
        PCICC32_LCR_ACCESS *pAccessOut;
 
        PCICC32_LCR_ACCESS *pAccessIn;
 
 
 
        SET_BUFFERS_METHOD_BUFFERED;
 
 
 
    KdPrint(("ioctl_access_lcr(%d)\n", wModuleNumber));
 
   
 
        pAccessOut = (PCICC32_LCR_ACCESS *)pOutputBuffer;
 
        pAccessIn  = (PCICC32_LCR_ACCESS *)pInputBuffer;
 
 
 
        // do here in between what has to be done -----------------
 
        if (OutputLength < sizeof(PCICC32_LCR_ACCESS))
 
                Status = STATUS_BUFFER_TOO_SMALL;
 
        else
 
        { 
 
                *pAccessOut = *pAccessIn;
 
                pAccessOut->dwInterface = wModuleNumber;
 
 
 
                if (pAccessIn->wRegisterAddress <= 0x52)
 
                {
 
                        // 1st part: long word accesses
 
                        if (pAccessIn->bBytesLane == LONG_ACCESS)
 
                        {
 
                                if (pAccessIn->wRegisterAddress & 0x0003)
 
                                        Status = STATUS_INSTRUCTION_MISALIGNMENT;
 
                                else
 
                                {
 
                                        ULONG       *pdwVirtAddress;
 
                                        ULONG           dwDummy;
 
 
 
                                        pdwVirtAddress = (ULONG *)((ULONG)pciada->pvVirtLcr + pAccessIn->wRegisterAddress);
 
 
 
                                        switch (pAccessIn->bAccessMode)
 
                                        {
 
                                                case LCR_WRITE: 
 
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, pAccessIn->dwContent);
 
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
 
                                                        break;
 
                                                case LCR_OR: 
 
                                                        dwDummy  = READ_REGISTER_ULONG(pdwVirtAddress);
 
                                                        dwDummy |= pAccessIn->dwContent;
 
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, dwDummy);
 
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
 
                                                        break;
 
                                                case LCR_AND: 
 
                                                        dwDummy  = READ_REGISTER_ULONG(pdwVirtAddress);
 
                                                        dwDummy &= pAccessIn->dwContent;
 
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, dwDummy);
 
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
 
                                                        break;
 
                                                case LCR_WRITE_ONLY: 
 
                                                        WRITE_REGISTER_ULONG(pdwVirtAddress, pAccessIn->dwContent);
 
                                                        break;
 
                                                case LCR_READ: 
 
                                                        pAccessOut->dwContent = READ_REGISTER_ULONG(pdwVirtAddress);
 
                                                        break;
 
 
 
                                                default: Status = STATUS_ILLEGAL_INSTRUCTION;
 
                                        }
 
                                }
 
                        }
 
 
 
                        // 2nd part: short word accesses
 
                        if (pAccessIn->bBytesLane == WORD_ACCESS)
 
                        {
 
                                if (pAccessIn->wRegisterAddress & 0x0001)
 
                                        Status = STATUS_INSTRUCTION_MISALIGNMENT;
 
                                else
 
                                {
 
                                        USHORT      *pwVirtAddress;
 
                                        USHORT          wDummy;
 
 
 
                                        pwVirtAddress = (USHORT *)((ULONG)pciada->pvVirtLcr + pAccessIn->wRegisterAddress);
 
 
 
                                        switch (pAccessIn->bAccessMode)
 
                                        {
 
                                                case LCR_WRITE: 
 
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, (USHORT)pAccessIn->dwContent);
 
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
 
                                                        break;
 
                                                case LCR_OR: 
 
                                                        wDummy  = READ_REGISTER_USHORT(pwVirtAddress);
 
                                                        wDummy |= (USHORT)pAccessIn->dwContent;
 
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, wDummy);
 
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
 
                                                        break;
 
                                                case LCR_AND: 
 
                                                        wDummy  = READ_REGISTER_USHORT(pwVirtAddress);
 
                                                        wDummy &= (USHORT)pAccessIn->dwContent;
 
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, wDummy);
 
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
 
                                                        break;
 
                                                case LCR_WRITE_ONLY: 
 
                                                        WRITE_REGISTER_USHORT(pwVirtAddress, (USHORT)pAccessIn->dwContent);
 
                                                        break;
 
                                                case LCR_READ: 
 
                                                        pAccessOut->dwContent = READ_REGISTER_USHORT(pwVirtAddress);
 
                                                        break;
 
 
 
                                                default: Status = STATUS_ILLEGAL_INSTRUCTION;
 
                                                        break;
 
                                        }
 
                                }
 
                        }
 
 
 
                        // 3rd part: check illegal byte lanes
 
                        if (!((pAccessIn->bBytesLane == LONG_ACCESS) || (pAccessIn->bBytesLane == WORD_ACCESS)))
 
                                Status = STATUS_ILLEGAL_INSTRUCTION;
 
                }
 
                else
 
                        Status = STATUS_ILLEGAL_INSTRUCTION;
 
        }       
 
        // do here in between what has to be done end -------------
 
 
 
        if (Status == STATUS_SUCCESS)           
 
                irp_info = sizeof(PCICC32_LCR_ACCESS);
 
 
 
        COMPLETE_REQUEST;
 
 
 
    KdPrint(("ioctl_access_lcr(), Status = 0x%08x\n", Status));
 
 
 
        return Status;
 
}
 
 
 
 
 
//------------------------------------------------------------------------
 
// the ultimate jumptable for ioctl
 
//
 
NTSTATUS (*ioctl[])(PDEVICE_OBJECT device_Obj, PIRP Irp, PIO_STACK_LOCATION IrpStack) =  
 
{
 
        ioctl_dummy,                                    // 0
 
        ioctl_dummy,                                    // 4
 
        ioctl_get_status,                               // 8
 
        ioctl_clear_status,                             // 0x0c
 
        ioctl_access_para,                              // 0x10
 
        ioctl_control_interrupts,       // 0x14
 
        ioctl_dummy,                    // 0x18
 
        ioctl_irq_status,               // 0x1c
 
        ioctl_access_lcr                // 0x20
 
};