//-------------------------------------------------------------------------
// 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
if (*n
== tolower(*ptr
))
{
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
;;
}