//-------------------------------------------------------------------------
// 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
};