//-------------------------------------------------------------------------
// WINNT driver for PCIVME interface from ARW Elektronik, Germany ---------
// the main body of the driver
//
// (c) 1999-2004 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
//
// $Log: pcivme_drv.c,v $
// Revision 1.3 2004/07/24 07:07:26 klaus
// Update copyright to 2004
//
//
// what who when
// started AR 15.06.1999
// first release 1.0 AR 17.10.1999
// fixed error in PLX9050Bug AR 28.02.2000
// PLX9050Bugfix bug fixed AR 03.03.2000
// PCICC32 CAMAC Interface conflict solved AR 03.03.2000
// Version 1.1 released AR 03.03.2000
// register all used resources, the idle too AR 25.11.2001
// changed resource allocation caused by WIN2000 AR 08.06.2002
//
//-------------------------------------------------------------------------
// INCLUDES
//
#include <initguid.h>
#include <wdmguid.h>
#include <ntddk.h>
#include <devioctl.h>
#include <pcivme_drv.h>
#include <pcivme_v.h>
#include <pcivme_io.h>
#include <pcivme_i.h>
#include <pcivme.h>
#include <pciif.h>
#include <pcivme_fifo.h>
//------------------------------------------------------------------------
// DEFINES
//
#define arraysize(p) (sizeof(p)/sizeof((p)[0]))
#ifndef DWORD
#define DWORD ULONG
#endif
#ifndef WORD
#define WORD USHORT
#endif
#define CTL_INDEX(x) ((x >> 2) & 0x7FF) // get user control code as index
#define IRQ_LIST_LENGTH 128 // max count of irqs in FIFO for each file_obj
#define RESOURCE_ENTRY_COUNT 6 // WIN2000 forces to claim all entries
#define DOS_DEVICE_NAME L"\\DosDevices\\PCIVME:"
//------------------------------------------------------------------------
// GLOBALS
//
//------------------------------------------------------------------------
// FUNCTIONS
//
//------------------------------------------------------------------------
// exchange the pointer to Bus Error
//
PBOOLEAN ExchangePointer(PBOOLEAN *current, PBOOLEAN next)
{
PBOOLEAN pb;
pb = *current;
*current = next;
return pb;
}
//------------------------------------------------------------------------
// get the vmemm number out of the filename
//
NTSTATUS InterpreteFileName(PCHAR name, int *nVmemm)
{
char *ptr = name;
char *n = "vmemm";
int h = -1; // high part
int l = -1; // low part
if (*ptr == '\\') ptr++; // jump over leading ...
while (*n) // compare the basename
{
n++;
ptr++;
}
else
return STATUS_NO_SUCH_FILE;
h = *ptr - '0'; // get the number
ptr++;
l = *ptr - '0';
if (*ptr == 0) // still over the end ??
{
l = h;
h = 0;
}
else
ptr++;
if ((h < 0) || (l < 0) || (*ptr != 0)) // anything wrong ??
return STATUS_NO_SUCH_FILE;
*nVmemm = (h * 10) + l; // calculate number
if (*nVmemm >= PCIVME_MAX_VMEMM) // out of range ??
return STATUS_NO_SUCH_FILE;
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// the ultimate driver unload
VOID PCIVMEUnload(PDRIVER_OBJECT driverObj)
{
int i;
UNICODE_STRING symbol_name;
if (!driverObj->DeviceObject) {
KdPrint(("PCIVMEUnload() DeviceObject does not exist \n"));
return;
}
DEVICE_EXT *ext = (DEVICE_EXT*)(driverObj->DeviceObject->DeviceExtension);
int nPCIADAs = ext->nPCIADAs;
PCIADA *pciada;
KdPrint(("PCIVMEUnload() InitState %d \n", ext->nInitState ));
if (ext->nInitState!=100) return;
switch (ext->nInitState)
{
case 8:
case 7:
// stop interrupts and shut off
PCIVMEDeInitPCIADAs(driverObj->DeviceObject);
PCIVMEDisConnectInterrupt(driverObj->DeviceObject);
// remove interrupt lists
for (i = 0; i < nPCIADAs; i++)
{
pciada = &ext->pciada[i];
// removeQueueFromList(...)
while (IsListEmpty(&pciada->IrqListList) == FALSE)
{
PLIST_ENTRY pList;
FIFO_LIST *next;
KdPrint(("RemoveHeadList(0x%08x)\n", &pciada->IrqListList));
pList = RemoveHeadList(&pciada->IrqListList);
next = CONTAINING_RECORD(pList, FIFO_LIST, entry);
ExFreePool((PVOID)next);
}
}
case 6:
// InitializeIRPQueue has no counterpart
case 5:
// KeInitializeDpc has no counterpart
case 4:
// release io spaces
for (i = 0; i < nPCIADAs; i++)
{
pciada = &ext->pciada[i];
if (pciada->pvVirtLcr != NULL)
MmUnmapIoSpace(pciada->pvVirtLcr, LCR_SPACE);
if (pciada->pvVirtIfr != NULL)
MmUnmapIoSpace(pciada->pvVirtIfr, IFR_SPACE);
}
case 3:
// HalGetInterruptVector has no counterpart
case 2:
// HalTranslateBusAddress has no counterpart
case 1:
// PCIVMEFreeResources(driverObj->DeviceObject); // not used in pnp
default:
case 0:
RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
// delete the symbolicLink in the registry
IoDeleteSymbolicLink( &symbol_name);
// delete the deviceObject
if (ext->LowerDeviceObject) IoDetachDevice(ext->LowerDeviceObject);
IoDeleteDevice(driverObj->DeviceObject);
}
KdPrint(("PCIVMEUnload() OK.\n"));
}
//------------------------------------------------------------------------
// called at CreateFile()
NTSTATUS PCIVMEOpen(PDEVICE_OBJECT deviceObj, PIRP Irp)
{
NTSTATUS result = STATUS_SUCCESS;
ANSI_STRING name;
int nVmemm;
int i;
DEVICE_EXT *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
PCIADA *pciada;
FILE_OBJ *file_obj = (FILE_OBJ *)NULL;
name.Buffer = NULL;
name.MaximumLength = 80;
result = RtlUnicodeStringToAnsiString(&name, &(Irp->Tail.Overlay.OriginalFileObject->FileName), TRUE);
if (result != STATUS_SUCCESS) goto fin;
result = InterpreteFileName(name.Buffer, &nVmemm);
if (result != STATUS_SUCCESS) goto fin;
KdPrint(("PCIVMEOpen(%d)\n", nVmemm));
RtlFreeAnsiString(&name);
file_obj = (FILE_OBJ *)ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_OBJ),'nepo');
if (file_obj == (FILE_OBJ *)NULL)
{
result = STATUS_NO_MEMORY;
goto fin;
}
file_obj->uwAssociatedVMEMM = (USHORT) nVmemm;
file_obj->bAddressModifier = 0x39;
file_obj->bAccessType = BYTE_ACCESS;
file_obj->bIncrement = BYTE_ACCESS; // increments each byte
file_obj->dwAccessBase = 0; // normal setting for all but extended
file_obj->bQueueIrq = FALSE;
result = InitializeFIFO(IRQ_LIST_LENGTH, &file_obj->pIrqListHandle);
if (result != STATUS_SUCCESS) goto fin;
Irp->Tail.Overlay.OriginalFileObject->FsContext = (PVOID)file_obj;
result = PCIVMEScanVMEMM(deviceObj);
if (result != STATUS_SUCCESS) goto fin;
for (i = 0; i < pDevExt->nPCIADAs; i++)
{
pciada = &pDevExt->pciada[i];
if (pciada->wModuleNumber == nVmemm)
{
pDevExt->vmemm[nVmemm] = pciada; // create association
pciada->dwLinkCount++;
break;
}
}
if (i >= pDevExt->nPCIADAs)
{
result = STATUS_NO_SUCH_FILE;
goto fin;
}
fin:
Irp->IoStatus.Status = result;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// be careful when releasing allocated memory !
if (result != STATUS_SUCCESS)
if (file_obj != (FILE_OBJ *)NULL)
if (file_obj->pIrqListHandle != (PVOID)NULL)
DestroyFIFO(file_obj->pIrqListHandle);
return result;
}
//------------------------------------------------------------------------
// called at close()
NTSTATUS PCIVMEClose(PDEVICE_OBJECT deviceObj, PIRP Irp)
{
DEVICE_EXT *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
FILE_OBJ *file_obj = (FILE_OBJ *)NULL;
PCIADA *pciada;
file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
KdPrint(("PCIVMEClose(%d)\n", file_obj->uwAssociatedVMEMM));
if (file_obj != (FILE_OBJ *)NULL)
{
pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
pciada->dwLinkCount--;
// remove the ListEntry(s) associated with this path
removeQueueFromList(file_obj, pciada);
// empty and remove the interrupt queue (if there is anything stored)
DestroyFIFO(file_obj->pIrqListHandle);
ExFreePool(file_obj);
Irp->Tail.Overlay.OriginalFileObject->FsContext = (FILE_OBJ *)NULL;
}
KdPrint(("PCIVMEClose OK\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// called at
NTSTATUS PCIVMEShutdown(PDEVICE_OBJECT deviceObj, PIRP irp )
{
UNREFERENCED_PARAMETER(irp);
KdPrint(("PCIVMEShutdown()\n"));
// deinit interfaces and interrupts
PCIVMEDeInitPCIADAs(deviceObj);
KdPrint(("PCIVMEShutdown() OK\n"));
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// called at ioctl()
NTSTATUS PCIVMEDeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
int nIndex;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
nIndex = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
KdPrint(("PCIVMEDeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
if (nIndex > CTL_INDEX(PCIVME_LAST_CTL_CODE))
{
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
KdPrint(("PCIVMEDeviceControl() FAIL.\n"));
return STATUS_UNSUCCESSFUL;
}
return ioctl[nIndex](deviceObj, Irp, IrpStack);
}
//------------------------------------------------------------------------
// called at read()
NTSTATUS PCIVMERead(PDEVICE_OBJECT device_Obj, PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
PVOID pOutputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
DEVICE_EXT *pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
PCIADA *pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
register ULONG Address = IrpStack->Parameters.Read.ByteOffset.LowPart + file_obj->dwAccessBase;
ULONG storeLength = 0;
PBOOLEAN pbPrevBusError;
KdPrint(("PCIVMERead(%d)\n", file_obj->uwAssociatedVMEMM));
// do here in between what has to be done -----------------
if (Address & file_obj->dwAddressMask) // don't do unaligned transfers
Status = STATUS_DATATYPE_MISALIGNMENT;
else
{
register ULONG Length = IrpStack->Parameters.Read.Length;
register ULONG blockLength;
register ULONG pageAddress;
register ULONG toNextPage;
KIRQL oldIrql;
Length &= ~file_obj->dwAddressMask; // align to integer increments
storeLength = Length;
// lock other users out
KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
// check for modifier
if (pciada->bModifier != file_obj->bAddressModifier)
{
WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
pciada->bModifier = file_obj->bAddressModifier;
}
// do the read ---
file_obj->bBusError = FALSE;
pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
while (Length)
{
pageAddress = Address & ~VME_ADR_MASK;
if (pageAddress != pciada->dwVMEPage)
{
WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
pciada->dwVMEPage = pageAddress;
}
toNextPage = (pageAddress + VME_ADR_MASK + 1) - Address;
blockLength = (toNextPage < Length) ? toNextPage : Length;
KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
Address, blockLength, Length));
file_obj->fRead(pOutputBuffer , blockLength, (PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)));
Length -= blockLength;
Address += blockLength;
pOutputBuffer = (PVOID)((PUCHAR)pOutputBuffer + blockLength);
}
// release the lock
KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
ExchangePointer(&pciada->pbBusError, pbPrevBusError);
if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
if (file_obj->bIncrement) // only when increment to next is on
*fileOffset =
RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
}
// do here in between what has to be done end -------------
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = storeLength;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
KdPrint(("PCIVMERead(), Status = 0x%08x\n", Status));
return Status;
}
//------------------------------------------------------------------------
// called at write()
NTSTATUS PCIVMEWrite(PDEVICE_OBJECT device_Obj, PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
PVOID pInputBuffer = ((void *)(MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority)));
LARGE_INTEGER *fileOffset = (LARGE_INTEGER *)&Irp->Tail.Overlay.OriginalFileObject->CurrentByteOffset;
FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
DEVICE_EXT *pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
PCIADA *pciada = pDevExt->vmemm[file_obj->uwAssociatedVMEMM];
register ULONG Address = IrpStack->Parameters.Write.ByteOffset.LowPart + file_obj->dwAccessBase;
ULONG storeLength = 0;
PBOOLEAN pbPrevBusError;
KdPrint(("PCIVMEWrite(%d)\n", file_obj->uwAssociatedVMEMM));
// do here in between what has to be done -----------------
if (Address & file_obj->dwAddressMask) // don't do unaligned transfers
Status = STATUS_DATATYPE_MISALIGNMENT;
else
{
register ULONG Length = IrpStack->Parameters.Write.Length;
register ULONG blockLength;
register ULONG pageAddress;
register ULONG toNextPage;
KIRQL oldIrql;
Length &= ~file_obj->dwAddressMask; // align to integer increments
storeLength = Length;
// check for modifier
// lock other users out
KeAcquireSpinLock(&pciada->AccessLock, &oldIrql);
if (pciada->bModifier != file_obj->bAddressModifier)
{
WRITE_REGISTER_UCHAR(pciada->pbModifier, file_obj->bAddressModifier);
pciada->bModifier = file_obj->bAddressModifier;
}
// do the read ---
file_obj->bBusError = FALSE;
pbPrevBusError = ExchangePointer(&pciada->pbBusError, &file_obj->bBusError);
while (Length)
{
pageAddress = Address & ~VME_ADR_MASK;
if (pageAddress != pciada->dwVMEPage)
{
WRITE_REGISTER_ULONG(pciada->pdwVMEAdr, pageAddress);
pciada->dwVMEPage = pageAddress;
}
toNextPage = (pageAddress + VME_ADR_MASK + 1) - Address;
blockLength = (toNextPage < Length) ? toNextPage : Length;
KdPrint(("Address 0x%08x, blockLength %d, Length %d\n",
Address, blockLength, Length));
file_obj->fWrite((PVOID)((PUCHAR)pciada->pvVME + (Address & VME_ADR_MASK)) , blockLength, pInputBuffer);
Length -= blockLength;
Address += blockLength;
pInputBuffer = (PVOID)((PUCHAR)pInputBuffer + blockLength);
}
// release the lock
KeReleaseSpinLock(&pciada->AccessLock, oldIrql);
ExchangePointer(&pciada->pbBusError, pbPrevBusError);
if (file_obj->bBusError) Status = STATUS_ACCESS_VIOLATION;
if (file_obj->bIncrement) // only when increment to next is on
*fileOffset = RtlLargeIntegerAdd(*fileOffset, RtlConvertUlongToLargeInteger(storeLength));
}
// do here in between what has to be done end -------------
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = storeLength;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
KdPrint(("PCIVMEWrite(), Status = 0x%08x\n", Status));
return Status;
}
#ifdef DO_CLEANUP
//------------------------------------------------------------------------
// called at cancel of a path
NTSTATUS PCIVMECancel(PDEVICE_OBJECT device_Obj, PIRP Irp)
{
FILE_OBJ *file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
PIRP pIrpCancel;
KdPrint(("PCIVMECancel()\n"));
// remove all queued IRPs of this file_obj
do
{
pIrpCancel = RemoveIRPfromQueue(device_Obj, file_obj);
if (pIrpCancel == (PIRP)NULL)
{
IoReleaseCancelSpinLock(pIrpCancel->CancelIrql);
break;
}
else
{
IoAcquireCancelSpinLock(pIrpCancel->CancelIrql);
// mark irp as not pending
IoSetCancelRoutine(pIrpCancel, NULL);
IoReleaseCancelSpinLock(pIrpCancel->CancelIrql);
pIrpCancel->IoStatus.Status = STATUS_CANCELLED;
pIrpCancel->IoStatus.Information = 0;
}
} while (pIrpCancel != (PIRP)NULL);
IoCompleteRequest(Irp, IO_NO_INCREMENT);
KdPrint(("PCIVMECancel(OK)\n"));
return STATUS_SUCCESS;
}
#endif
// http://read.pudn.com/downloads148/sourcecode/windows/vxd/640413/agp/agplib/init.c__.htm
NTSTATUS
QueryBusInterface(
IN PDEVICE_OBJECT DeviceObject,
OUT PBUS_INTERFACE_STANDARD BusInterface
)
/*++
Routine Description:
Sends a query-interface IRP to the specified device object
to obtain the BUS_INTERFACE_STANDARD interface.
Arguments:
DeviceObject - Supplies the device object to send the BUS_INTERFACE_STANDARD to
BusInterface - Returns the bus interface
Return Value:
STATUS_SUCCESS if successful
NTSTATUS if unsuccessful
--*/
{
PIRP Irp;
KEVENT Event;
PIO_STACK_LOCATION IrpSp;
IO_STATUS_BLOCK IoStatusBlock;
NTSTATUS Status;
// ULONG ReturnLength;
KeInitializeEvent( &Event, NotificationEvent, FALSE );
Irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
DeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock );
if (Irp == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
IrpSp = IoGetNextIrpStackLocation( Irp );
ASSERT(IrpSp != NULL);
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
IrpSp->MajorFunction = IRP_MJ_PNP;
IrpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
IrpSp->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
IrpSp->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
IrpSp->Parameters.QueryInterface.Version = 1;
IrpSp->Parameters.QueryInterface.Interface = (PINTERFACE) BusInterface;
IrpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, NULL );
Status = Irp->IoStatus.Status;
}
return(Status);
}
//------------------------------------------------------------------------
// search for pciada's
//
NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
{
PCI_SLOT_NUMBER SlotNumber;
PCI_COMMON_CONFIG pci_config;
PBUS_INTERFACE_STANDARD busInterface;
PCIADA *pciada;
ULONG propertyAddress, length;
USHORT FunctionNumber, DeviceNumber;
int *found;
int i;
NTSTATUS status;
int BytesRead;
KdPrint(("SearchDevices()\n"));
// prepare structures ----------------------------------------
found = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
*found = 0;
for (i = 0; i < PCIVME_MAX_PCIADA; i++)
{
pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
pciada->Bus = -1;
pciada->Slot.u.AsULONG = 0xFFFFFFFF;
}
// search for pciada's ---------------------------------------
SlotNumber.u.bits.Reserved = 0;
busInterface = (PBUS_INTERFACE_STANDARD)ExAllocatePool(NonPagedPool,
sizeof(BUS_INTERFACE_STANDARD));
if (busInterface == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
((DEVICE_EXT*)(device_Obj->DeviceExtension))->busInterface = busInterface;
status = QueryBusInterface(device_Obj, busInterface);
BytesRead = busInterface->GetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, &pci_config, 0, PCI_COMMON_HDR_LENGTH);
pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[0];
//http://www.hollistech.com/Resources/Misc%20articles/getbusdata.htm
//IoGetDeviceProperty
//There are other differnt methods to send a request to lower layer. One method is
//by sending IRP_MN_READ_CONFIG to lower driver. You will recieve
//PCI_COMMON_CONFIG structure.
// http://msdn.microsoft.com/en-us/library/windows/hardware/ff536890(v=vs.85).aspx
// http://www.rdos.net/svn/tags/V9.2.5/watcom/bld/src/win32/miniwdm/dev/wdmdev.c
if ((pci_config.VendorID == PCIVME_VENDOR_ID) &&
(pci_config.DeviceID == PCIVME_DEVICE_ID) &&
(pci_config.u.type0.SubSystemID == PCIVME_SUBSYS_ID) &&
(pci_config.u.type0.SubVendorID == PCIVME_SUBVEN_ID) &&
(pci_config.u.type0.BaseAddresses[2]))
{
pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found];
memcpy(&pciada
->PCIDevice
, &pci_config
, sizeof(pci_config
));
IoGetDeviceProperty(device_Obj,
DevicePropertyBusNumber,
sizeof(ULONG),
(PVOID)&(pciada->Bus),
&length);
IoGetDeviceProperty(device_Obj,
DevicePropertyAddress,
sizeof(ULONG),
(PVOID)&propertyAddress,
&length);
//
// For PCI, the DevicePropertyAddress has device number
// in the high word and the function number in the low word.
//
FunctionNumber = (USHORT)((propertyAddress)& 0x0000FFFF);
DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
pciada->Slot.u.AsULONG = DeviceNumber;
KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
(*found)++;
if (*found >= PCIVME_MAX_PCIADA) return STATUS_SUCCESS;
}
KdPrint(("SearchDevices() found %d devices\n", (*found)));
return STATUS_SUCCESS;
}
//---------------------------------------------------------------
// function to call for bug fix of PLX9050 build in bug
//
NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
{
// http://permalink.gmane.org/gmane.linux.kernel.pci/18419
DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
int i;
ULONG dwData;
PCIADA *pciada;
PBUS_INTERFACE_STANDARD busInterface;
KdPrint(("PLX9050BugFix()\n"));
busInterface = DeviceExtension->busInterface;
for (i = 0; i < DeviceExtension->nPCIADAs; i++)
{
pciada = &DeviceExtension->pciada[i];
if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[0]) & 0x80)
{
KdPrint(("Changing address 0:0x%p with 4:0x%p\n",
pciada->PCIDevice.u.type0.BaseAddresses[0],
pciada->PCIDevice.u.type0.BaseAddresses[4]));
pciada->PCIDevice.u.type0.BaseAddresses[0] = // exchange
pciada->PCIDevice.u.type0.BaseAddresses[4];
pciada->PCIDevice.u.type0.BaseAddresses[4] = dwData;
if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0], 0x10, 4) != 4)
return STATUS_UNSUCCESSFUL;
if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[4], 0x20, 4) != 4)
return STATUS_UNSUCCESSFUL;
}
if ((dwData = pciada->PCIDevice.u.type0.BaseAddresses[1]) & 0x80)
{
KdPrint(("Changing address 1:0x%p with 5:0x%p\n",
pciada->PCIDevice.u.type0.BaseAddresses[1],
pciada->PCIDevice.u.type0.BaseAddresses[5]));
pciada->PCIDevice.u.type0.BaseAddresses[1] = // exchange
pciada->PCIDevice.u.type0.BaseAddresses[5];
pciada->PCIDevice.u.type0.BaseAddresses[5] = dwData;
if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1], 0x14, 4) != 4)
return STATUS_UNSUCCESSFUL;
if (busInterface->SetBusData(busInterface->Context, PCI_WHICHSPACE_CONFIG, (PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5], 0x24, 4) != 4)
return STATUS_UNSUCCESSFUL;
}
}
return STATUS_SUCCESS;
}
static VOID ShowResources(IN PCM_PARTIAL_RESOURCE_LIST list)
{ // ShowResources
PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = list->PartialDescriptors;
ULONG nres = list->Count;
ULONG i;
for (i = 0; i < nres; ++i, ++resource)
{ // for each resource
ULONG type = resource->Type;
static char* namelow[] = {
"CmResourceTypeNull",// 0 // ResType_All or ResType_None (0x0000)
"CmResourceTypePort",// 1 // ResType_IO (0x0002)
"CmResourceTypeInterrupt",// 2 // ResType_IRQ (0x0004)
"CmResourceTypeMemory",// 3 // ResType_Mem (0x0001)
"CmResourceTypeDma",// 4 // ResType_DMA (0x0003)
"CmResourceTypeDeviceSpecific",// 5 // ResType_ClassSpecific (0xFFFF)
"CmResourceTypeBusNumber",// 6 // ResType_BusNumber (0x0006)
"CmResourceTypeMemoryLarge" // 7 // ResType_MemLarge (0x0007)
};
static char* namehigh[] = {
//"CmResourceTypeNonArbitrated" ,// 128 // Not arbitrated if 0x80 bit set
"CmResourceTypeConfigData",// 128 // ResType_Reserved (0x8000)
"CmResourceTypeDevicePrivate",// 129 // ResType_DevicePrivate (0x8001)
"CmResourceTypePcCardConfig",// 130 // ResType_PcCardConfig (0x8002)
"CmResourceTypeMfCardConfig",// 131 // ResType_MfCardConfig (0x8003)
"CmResourceTypeConnection" // 132 // ResType_Connection (0x8004)
};
if (type<8) KdPrint((" [%d] type %s", type, type < arraysize(namelow) ? namelow[type] : "unknown"));
if (type>127) KdPrint((" [%d] type %s", type, type-128 < arraysize(namehigh) ? namehigh[type-128] : "unknown"));
switch (type)
{ // select on resource type
case CmResourceTypePort:
KdPrint((" start ADDR=0x%p 0x%8X%8.8lX length %X\n",
resource->u.Port.Start, resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
resource->u.Port.Length));
break;
case CmResourceTypeMemory:
KdPrint((" %d start ADDR=0x%p \n", i, resource->u.Memory.Start ));
break;
case CmResourceTypeInterrupt:
KdPrint((" IRQL %d, vector %d, affinity %d\n",
resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
resource->u.Interrupt.Affinity));
break;
case CmResourceTypeDma:
KdPrint((" channel %d, port %X\n",
resource->u.Dma.Channel, resource->u.Dma.Port));
} // select on resource type
} // for each resource
} // ShowResources
//------------------------------------------------------------------------
// reserve resources for PCIADAs
//
NTSTATUS PCIVMEExtractResources(PCIADA *pciada, PIRP irp)
{
//PCM_RESOURCE_LIST pResourceList;
///PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
PCM_PARTIAL_RESOURCE_LIST pPartialList = NULL;
PCM_PARTIAL_RESOURCE_LIST pListTranslated = NULL;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
int i;
int bug = 0;
KdPrint(("PCIVMEExtractResources()\n"));
///pResourceList = pList;
///pFullDescriptor = pResourceList->List;
///pPartialList = &pFullDescriptor->PartialResourceList;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
if (stack->Parameters.StartDevice.AllocatedResources)
pPartialList = &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList;
KdPrint(("Allocated Resources:------------------\n"));
ShowResources(pPartialList);
int plcount = 0;
for (i=0; i<(int)pPartialList->Count; i++)
{
pPartialDescriptor = &pPartialList->PartialDescriptors[i];
switch (pPartialDescriptor->Type)
{
case CmResourceTypeInterrupt:
pciada->Irql = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
pciada->Vector = pPartialDescriptor->u.Interrupt.Vector;
pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
KdPrint(("AllocatedResources Irq : Irql: %d, Vector: %d, Affinity: %d\n",
pciada->Irql, pciada->Vector, pciada->Affinity));
break;
case CmResourceTypeDma:
KdPrint(("AllocatedResources Dma : \n"));
break;
case CmResourceTypePort:
KdPrint(("AllocatedResources Port : 0x%p\n", pPartialDescriptor->u.Port.Start));
break;
case CmResourceTypeMemory:
// special handling of PLXBUG here because of WIN2000
// WIN2000 doesn't recognize late address changes
if (!bug)
{
if (plcount == 0)
{
pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
if (pciada->pvPhysLcr.LowPart & 0x80) {
bug = 1;
KdPrint(("AllocatedResources PLXBug\n"));
}
}
}
else
{
if (plcount == 3)
pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
}
if (plcount == 2){
pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
KdPrint(("PCIVMEExtractResources() IFR=0x%p \n", pciada->pvPhysIfr));
}
KdPrint(("[%d] AllocatedResources Memory : 0x%p\n", plcount, (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
break;
}
if (pPartialDescriptor->Type < 8) plcount++;
}
KdPrint(("PCIVMEExtractResources() LCR=0x%p IFR=0x%p \n", pciada->pvPhysLcr, pciada->pvPhysIfr));
if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
pListTranslated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
KdPrint(("Translated Resources:------------------\n"));
ShowResources(pListTranslated);
plcount = 0;
bug = 0;
for (i = 0; i<(int)pPartialList->Count; i++)
{
pPartialDescriptor = &pListTranslated->PartialDescriptors[i];
switch (pPartialDescriptor->Type)
{
case CmResourceTypeInterrupt:
pciada->Irql = (KIRQL)pPartialDescriptor->u.Interrupt.Level;
pciada->Vector = pPartialDescriptor->u.Interrupt.Vector;
pciada->Affinity = pPartialDescriptor->u.Interrupt.Affinity;
KdPrint(("AllocatedResourcesTranslated Irq : Irql: %d, Vector: %d, Affinity: %d\n",
pciada->Irql, pciada->Vector, pciada->Affinity));
break;
case CmResourceTypeDma:
KdPrint(("AllocatedResourcesTranslated Dma : \n"));
break;
case CmResourceTypePort:
KdPrint(("AllocatedResourcesTranslated Port : 0x%p\n", pPartialDescriptor->u.Port.Start));
break;
case CmResourceTypeMemory:
// special handling of PLXBUG here because of WIN2000
// WIN2000 doesn't recognize late address changes
if (!bug)
{
if (plcount == 0)
{
pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
KdPrint(("0 PCIVMEExtractResources() LCR=0x%p \n", pciada->pvPhysLcr));
if (pciada->pvPhysLcr.LowPart & 0x80) {
bug = 1;
KdPrint(("AllocatedResourcesTranslated PLXBug\n"));
}
}
}
else
{
if (plcount == 3){
pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
KdPrint(("3 PCIVMEExtractResources() LCR=0x%p \n", pciada->pvPhysLcr));
}
}
if (plcount == 2){
pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
KdPrint(("2 PCIVMEExtractResources() IFR=0x%p \n", pciada->pvPhysIfr));
}
KdPrint(("[%d] AllocatedResourcesTranslated Memory : 0x%p\n", plcount, (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
break;
}
if (pPartialDescriptor->Type < 8) plcount++;
}
if (pciada->Irql == 0)
return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
KdPrint(("PCIVMEExtractResources() Translated LCR=0x%p IFR=0x%p \n", pciada->pvPhysLcr, pciada->pvPhysIfr));
return STATUS_SUCCESS;
}
NTSTATUS PCIVMEReserveResources(PDEVICE_OBJECT device_Obj, PIRP irp)
{
//PCM_RESOURCE_LIST pList = NULL;
NTSTATUS result = STATUS_SUCCESS;
int i;
DEVICE_EXT *pDevExt = (DEVICE_EXT*)(device_Obj->DeviceExtension);
int nPCIADAs = pDevExt->nPCIADAs;
PCIADA *pciada;
UNICODE_STRING DriverClassName;
KdPrint(("PCIVMEReserveResources()\n"));
// prepare resource claiming
//RtlInitUnicodeString(&DriverClassName, L"PCICC32");
RtlInitUnicodeString(&DriverClassName, L"PCIVME");
// cycle through all busses and slots assigned to PCIADAs
for (i = 0; i < nPCIADAs; i++)
{
pciada = &pDevExt->pciada[i];
//result = HalAssignSlotResources(NULL, &DriverClassName, device_Obj->DriverObject, device_Obj,
// PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, &pList);
/*
result = IoReportDetectedDevice(device_Obj->DriverObject, PCIBus, pciada->Bus, pciada->Slot.u.AsULONG, pList, NULL, FALSE, &device_Obj);
if (result != STATUS_SUCCESS){
KdPrint(("PCIVMEReserveResources(0x%08x) HalAssignSlotResources ***ERROR*** faliure to get slot information\n", result));
break;
}
*/
result = PCIVMEExtractResources(pciada, irp);
if (result != STATUS_SUCCESS){
KdPrint(("PCIVMEReserveResources(0x%08x) PCIVMEExtractResources\n", result));
break;
}
}
// its my part to free allocated resources
//if (pList != NULL) ExFreePoolWithTag(pList,'nepo');
KdPrint(("PCIVMEReserveResources(0x%08x)\n", result));
return result;
};
//------------------------------------------------------------------------
// translate memory resources to neutral for PCIADAs
//
NTSTATUS PCIVMETranslateBusAddresses(PDEVICE_OBJECT device_Obj, PIRP irp)
{
int i;
NTSTATUS result = STATUS_SUCCESS;
int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
ULONG memType0, memType2;
PCIADA *pciada;
PCM_PARTIAL_RESOURCE_LIST pPartialList = NULL;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(irp);
if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
pPartialList = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
for (i = 0; i < nPCIADAs; i++)
{
pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
memType0 = memType2 = 0;
/*
if (!(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysLcr, &memType0,
&pciada->pvPhysLcr)) ||
!(HalTranslateBusAddress(PCIBus, pciada->Bus, pciada->pvPhysIfr, &memType2,
&pciada->pvPhysIfr)))
{
result = STATUS_UNSUCCESSFUL;
break;
}
*/
KdPrint(("PCIADA %d TranslateBusAddresseses() -- no translation is made\n", i));
if ((memType0) || (memType2))
{
result = STATUS_UNSUCCESSFUL;
break;
}
}
return result;
}
//------------------------------------------------------------------------
// map address spaces to virtual addresses
//
NTSTATUS PCIVMEMapIOspace(PDEVICE_OBJECT device_Obj)
{
int i;
DEVICE_EXT *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
int nPCIADAs = pDevExt->nPCIADAs;
PCIADA *pciada;
KdPrint(("PCIVMEMapIOspace()\n"));
for (i = 0; i < nPCIADAs; i++)
{
pciada = &pDevExt->pciada[i];
if ((pciada->pvVirtLcr = MmMapIoSpace(pciada->pvPhysLcr, LCR_SPACE, FALSE)) == NULL)
return STATUS_UNSUCCESSFUL;
if ((pciada->pvVirtIfr = MmMapIoSpace(pciada->pvPhysIfr, IFR_SPACE, FALSE)) == NULL)
return STATUS_UNSUCCESSFUL;
KdPrint(("PCIADA %d: LCR 0x%08x IFR 0x%08x\n",
i, pciada->pvVirtLcr, pciada->pvVirtIfr));
pciada->pwIntCSR = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x4C);
pciada->pwCntrl = (PUSHORT)((PUCHAR)pciada->pvVirtLcr + 0x50);
}
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// initializes and registers a DPC routine for each pciada
//
NTSTATUS InitializeCustomDPCObjects(PDEVICE_OBJECT device_object)
{
int i;
int nPCIADAs = ((DEVICE_EXT*)(device_object->DeviceExtension))->nPCIADAs;
PCIADA *pciada;
KdPrint(("InitializeCustomDPCObject()\n"));
for (i = 0; i < nPCIADAs; i++)
{
pciada = &((DEVICE_EXT*)(device_object->DeviceExtension))->pciada[i];
KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
}
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// initializes the queue for storing IRPs waiting for vectors
//
NTSTATUS InitializeIRPQueue(PDEVICE_OBJECT device_Obj)
{
DEVICE_EXT *pDevExt = ((DEVICE_EXT*)(device_Obj->DeviceExtension));
KdPrint(("InitializeIRPQueue()\n"));
KeInitializeSpinLock(&pDevExt->IRPLock);
InitializeListHead(&pDevExt->IRPList);
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// init structures a.s.o.
//
VOID PCIVMESoftInit(PDEVICE_OBJECT device_Obj)
{
int i;
PCIADA *pciada;
for (i = 0; i < PCIVME_MAX_PCIADA; i++)
{
pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[i];
pciada->pvPhysLcr.QuadPart = pciada->pvPhysIfr.QuadPart = 0;
pciada->pvVirtLcr = pciada->pvVirtIfr = NULL;
pciada->bConnected = FALSE; // connection still not verified
pciada->bWordMode = TRUE;
pciada->bSysControl = FALSE;
pciada->wModuleNumber = 0xFFFF;
pciada->wFPGAVersion = 0xFFFF;
pciada->wModuleType = 1; // always VMEMM
pciada->InterruptObject = NULL;
pciada->Irql = 0;
pciada->Vector = 0;
pciada->Affinity = 0;
pciada->dwLinkCount = 0;
KeInitializeSpinLock(&pciada->IrqListLock);
KeInitializeSpinLock(&pciada->AccessLock);
InitializeListHead(&pciada->IrqListList); // start of list of irq fifos
pciada->nInterruptHandlers = 0;
}
// no vmemm associated to any PCIADA
for (i = 0; i < PCIVME_MAX_VMEMM; i++)
((DEVICE_EXT*)(device_Obj->DeviceExtension))->vmemm[i] = NULL;
}
NTSTATUS OnRequestComplete(PDEVICE_OBJECT fdo, PIRP Irp, PKEVENT pev)
{
UNREFERENCED_PARAMETER(fdo);
UNREFERENCED_PARAMETER(Irp);
KeSetEvent(pev, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS CompleteRequest(PIRP Irp, NTSTATUS status, ULONG_PTR Information)
{
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = Information;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS ForwardAndWait(PDEVICE_OBJECT fdo, PIRP Irp)
{
KEVENT event;
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE) OnRequestComplete, (PVOID)&event, TRUE, TRUE, TRUE);
PDEVICE_EXT pdx = (PDEVICE_EXT ) fdo->DeviceExtension;
IoCallDriver(pdx->LowerDeviceObject, Irp);
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
return Irp->IoStatus.Status;
}
NTSTATUS HandleStartDevice(PDEVICE_OBJECT fdo, PIRP Irp)
{
PIO_STACK_LOCATION stack;
Irp->IoStatus.Status = STATUS_SUCCESS;
NTSTATUS status = ForwardAndWait(fdo, Irp);
if (!NT_SUCCESS(status))
return CompleteRequest(Irp, status, Irp->IoStatus.Information);
stack = IoGetCurrentIrpStackLocation(Irp);
status = PCIVMEStartDevice(fdo, Irp);
return CompleteRequest(Irp, status, Irp->IoStatus.Information);
}
NTSTATUS DefaultPnpHandler(PDEVICE_OBJECT fdo, PIRP Irp)
{
IoSkipCurrentIrpStackLocation(Irp);
PDEVICE_EXT pdx = (PDEVICE_EXT )fdo->DeviceExtension;
return IoCallDriver(pdx->LowerDeviceObject, Irp);
}
NTSTATUS HandleStopDevice(PDEVICE_OBJECT fdo, PIRP Irp)
{
IoSkipCurrentIrpStackLocation(Irp);
UNICODE_STRING symbol_name;
RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
// delete the symbolicLink in the registry
IoDeleteSymbolicLink(&symbol_name);
DEVICE_EXT *ext = (DEVICE_EXT*)(fdo->DeviceExtension);
// delete the busInterface and deviceObject
if (ext->busInterface) {
(*ext->busInterface->InterfaceDereference)(ext->busInterface->Context);
ext->busInterface = NULL;
}
if (ext->LowerDeviceObject) IoDetachDevice(ext->LowerDeviceObject);
IoDeleteDevice(fdo);
KdPrint(("HandleStopDevice (OK)\n"));
return STATUS_SUCCESS;
}
NTSTATUS PCIVMEDispatchPnp(PDEVICE_OBJECT fdo, PIRP Irp)
{
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG fcn = stack->MinorFunction;
static char* pnpname[] = {
"IRP_MN_START_DEVICE",
"IRP_MN_QUERY_REMOVE_DEVICE",
"IRP_MN_REMOVE_DEVICE",
"IRP_MN_CANCEL_REMOVE_DEVICE",
"IRP_MN_STOP_DEVICE",
"IRP_MN_QUERY_STOP_DEVICE",
"IRP_MN_CANCEL_STOP_DEVICE",
"IRP_MN_QUERY_DEVICE_RELATIONS",
"IRP_MN_QUERY_INTERFACE",
"IRP_MN_QUERY_CAPABILITIES",
"IRP_MN_QUERY_RESOURCES",
"IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
"IRP_MN_QUERY_DEVICE_TEXT",
"IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
"",
"IRP_MN_READ_CONFIG",
"IRP_MN_WRITE_CONFIG",
"IRP_MN_EJECT",
"IRP_MN_SET_LOCK",
"IRP_MN_QUERY_ID",
"IRP_MN_QUERY_PNP_DEVICE_STATE",
"IRP_MN_QUERY_BUS_INFORMATION",
"IRP_MN_DEVICE_USAGE_NOTIFICATION",
"IRP_MN_SURPRISE_REMOVAL",
"IRP_MN_QUERY_LEGACY_BUS_INFORMATION",
};
if (fcn < arraysize(pnpname))
KdPrint(("PCIVMEDispatchPnp - IRP_MJ_PNP (%s)\n", pnpname[fcn]));
else
KdPrint(( "PCIVMEDispatchPnp - IRP_MJ_PNP (%2.2X)\n", fcn));
static NTSTATUS(*fcntab[])(PDEVICE_OBJECT, PIRP) = {
HandleStartDevice, // IRP_MN_START_DEVICE
// DefaultPnpHandler, // IRP_MN_QUERY_REMOVE_DEVICE
HandleStopDevice // IRP_MN_REMOVE_DEVICE
};
if (fcn >= arraysize(fcntab))
return DefaultPnpHandler(fdo, Irp);
return (*fcntab[fcn])(fdo, Irp);
}
NTSTATUS PCIVMEStartDevice(PDEVICE_OBJECT device_object, PIRP irp){
NTSTATUS result = STATUS_SUCCESS;
int nPCIADAs; // count of PCIADAs
DEVICE_EXT *DeviceExtension = NULL;
DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
// init pciada structures ------------------------------------
PCIVMESoftInit(device_object);
// search for PCIADAs ----------------------------------------
result = SearchDevices(device_object);
nPCIADAs = DeviceExtension->nPCIADAs;
if ((result != STATUS_SUCCESS) || !(nPCIADAs))
{
KdPrint(("PCIVMEStartDevice Device not found\n"));
PCIVMEUnload(DeviceExtension->driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
// request exclusive ownership of .. ---------------------------------
if ((result = PCIVMEReserveResources(device_object, irp)) != STATUS_SUCCESS)
{
KdPrint(("PCIVMEStartDevice Resource not reserved PCIVMEReserveResources \n"));
PCIVMEUnload(DeviceExtension->driverObj);
return result;
}
else
DeviceExtension->nInitState++;
// fix PLX9050 Bug -------------------------------------------
if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
{
KdPrint(("PCIVMEStartDevice PLX9050BugFix\n"));
PCIVMEUnload(DeviceExtension->driverObj);
return result;
}
DeviceExtension->nInitState += 2;
/*
// translate BUS relative addresses ----------------------------------
if ((result = PCIVMETranslateBusAddresses(device_object,irp)) != STATUS_SUCCESS)
{
PCIVMEUnload(DeviceExtension->driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
// translate Interrupt Resources used --------------------------------
if ((result = PCIVMETranslateInterrupts(device_object)) != STATUS_SUCCESS)
{
PCIVMEUnload(DeviceExtension->driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
*/
// map address spaces to virtual addresses ---------------------------
if ((result = PCIVMEMapIOspace(device_object)) != STATUS_SUCCESS)
{
PCIVMEUnload(DeviceExtension->driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
// initialze my custom DPC objects -----------------------------------
if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
{
PCIVMEUnload(DeviceExtension->driverObj);
return result;
}
else
DeviceExtension->nInitState++;
// initialze the queue for IRPs waiting for vectors ------------------
if ((result = InitializeIRPQueue(device_object)) != STATUS_SUCCESS)
{
PCIVMEUnload(DeviceExtension->driverObj);
return result;
}
else
DeviceExtension->nInitState++;
// connect interrupts to service routines ----------------------------
if ((result = PCIVMEConnectInterrupt(device_object)) != STATUS_SUCCESS)
{
PCIVMEUnload(DeviceExtension->driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
// scan all connected VMEMM for info and later use -------------------
if ((result = PCIVMEScanVMEMM(device_object)) != STATUS_SUCCESS)
{
PCIVMEUnload(DeviceExtension->driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
device_object->Flags &= ~DO_DEVICE_INITIALIZING;
return result;
}
NTSTATUS PCIVMEAddDevice(PDRIVER_OBJECT driverObj, PDEVICE_OBJECT pdo)
{ // AddDevice
UNICODE_STRING device_name;
UNICODE_STRING symbol_name;
NTSTATUS result = STATUS_SUCCESS;
//int nPCIADAs; // count of PCIADAs
DEVICE_EXT *DeviceExtension = NULL;
PDEVICE_OBJECT device_object;
RtlInitUnicodeString(&device_name, L"\\Device\\PCIVME");
KdPrint(("PCIVME AddDevice() v%d.%d\n", (DRIVER_VERSION >> 16) & 0xff, DRIVER_VERSION & 0xff));
/* DeviceObject durch IO-Manager erzeugen */
result = IoCreateDevice( driverObj, // DriverObject received by the DriverEntry Call
sizeof(DEVICE_EXT), // required Memory for the DeviceExtension
&device_name, // Name of the device in the device-Directory
FILE_DEVICE_UNKNOWN, // Device-ID
0, // Device-Characteristics normal 0
FALSE, // TRUE : one Thread can open the driver
&device_object); // DeviceObject returned from the IO-Manager
// defines how the data are handled between user / kernel Adress-Space
device_object->Flags |= DO_DIRECT_IO;
#if 0
// register the shutdown notification entry
IoRegisterShutdownNotification(device_object);
#endif
// anounce driver as symbolic device ---------------------------------
if (result == STATUS_SUCCESS)
{
/* now the symbolic Link is created. If there is no S.L. a program cannot connect to the driver */
RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
result = IoCreateSymbolicLink(&symbol_name,&device_name);
if (result != STATUS_SUCCESS)
{
IoDeleteDevice(device_object);
return result;
}
}
else
return result;
DeviceExtension = (DEVICE_EXT*)device_object->DeviceExtension;
DeviceExtension->actualIrp = NULL;
DeviceExtension->driverObj = driverObj;
DeviceExtension->nInitState = 0;
DeviceExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack(device_object, pdo);
KdPrint(("AddDevice() OK.\n"));
return result;
}
//------------------------------------------------------------------------
// the ultimate starting point of a driver
NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
{
UNREFERENCED_PARAMETER(regPath);
KdPrint(("PCIVME DriverEntry() v%d.%d\n", (DRIVER_VERSION >> 16) & 0xff, DRIVER_VERSION & 0xff));
driverObj->DriverUnload = PCIVMEUnload;
driverObj->DriverExtension->AddDevice = PCIVMEAddDevice;
driverObj->MajorFunction[IRP_MJ_CREATE] = PCIVMEOpen;
driverObj->MajorFunction[IRP_MJ_CLOSE] = PCIVMEClose;
driverObj->MajorFunction[IRP_MJ_READ] = PCIVMERead;
driverObj->MajorFunction[IRP_MJ_WRITE] = PCIVMEWrite;
driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PCIVMEDeviceControl;
#ifdef DO_CLEANUP
driverObj->MajorFunction[IRP_MJ_CLEANUP] = PCIVMECancel;
#endif
driverObj->MajorFunction[IRP_MJ_SHUTDOWN] = PCIVMEShutdown;
driverObj->MajorFunction[IRP_MJ_PNP] = PCIVMEDispatchPnp;
return STATUS_SUCCESS;;
}