//-------------------------------------------------------------------------
// WINNT driver for PCICC32 (CAMAC) interface of ARW Elektronik, Germany --
// the main body of the driver
//
// (c) 2000-2002 ARW Elektronik
//
// this source code is published under GPL (Open Source). You can use, redistribute 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 out of pcivme sources AR 25.03.2000
// added IRQ handling AR 24.02.2001
// Added AUTOREAD functionality AR 17.03.2001
// Added LCR_READ AR 31.03.2001
// resource allocation registers idle entries too AR 25.11.2001
// changed making procedure (only VCC > 6.0) AR 30.05.2002
// totally rearanged resource alloc for WIN2000 AR 01.06.2002
// version 2.14 eleminates PLXBUG in WIN2000 AR 05.06.2002
// added KeSynchronizeExecution for interrupt sync AR 16.06.2002
//
//------------------------------------------------------------------------
// DEFINES
//
#ifndef DWORD
#define DWORD ULONG
#endif
#ifndef WORD
#define WORD USHORT
#endif
#define CTL_INDEX(x) ((x >> 2) & 0xFF) // get user control code as index
#define RESOURCE_ENTRY_COUNT 6 // WIN2000 forces to claim all entries
#define DOS_DEVICE_NAME L"\\DosDevices\\PCICC32:"
//-------------------------------------------------------------------------
// INCLUDES
//
#include <ntddk.h>
#include <devioctl.h>
// #include <wdm.h>
#include <pcicc32_drv.h>
#include <pcicc32.h>
#include <pcicc32_v.h>
#include <pcicc32_i.h>
#include <pcicc32_io.h>
//------------------------------------------------------------------------
// TYPEDEFS
//
typedef struct
{
FILE_OBJ *file_obj;
PCIADA *pciada;
PVOID pOutputBuffer;
PVOID pInputBuffer;
ULONG Address;
DWORD Length;
} SYNC_CONTEXT;
//------------------------------------------------------------------------
// GLOBALS
//
//------------------------------------------------------------------------
// FUNCTIONS
//
//------------------------------------------------------------------------
// for debug only - print interrupt line
//
#if DBG
void PrintInterruptLine(int Bus, int Slot)
{
PCI_COMMON_CONFIG pci_config;
HalGetBusData( PCIConfiguration, // Bustype
Bus, // PCI-Busnumber
Slot, // Slotnumber
(PVOID) &(pci_config), // Pointer for the PCI-Information
sizeof(PCI_COMMON_CONFIG));
KdPrint(("Irql: %d\n", pci_config.u.type0.InterruptLine));
}
#endif
//------------------------------------------------------------------------
// get the cc32 number out of the filename
//
NTSTATUS InterpreteFileName(PCHAR name, int *nCC32)
{
char *ptr = name;
char *n = "cc32_";
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;
*nCC32 = (h * 10) + l; // calculate number
if (*nCC32 >= PCICC32_MAX_CC32) // out of range ??
return STATUS_NO_SUCH_FILE;
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// the ultimate driver unload
VOID PCICC32Unload(PDRIVER_OBJECT driverObj)
{
int i;
UNICODE_STRING symbol_name;
DEVICE_EXT *ext = (DEVICE_EXT*)(driverObj->DeviceObject->DeviceExtension);
int nPCIADAs = ext->nPCIADAs;
PCIADA *pciada;
KdPrint(("PCICC32Unload()\n"));
switch (ext->nInitState)
{
case 8:
case 7:
case 6:
// stop interrupts and shut off
PCICC32DeInitPCIADAs(driverObj->DeviceObject);
PCICC32DisConnectInterrupt(driverObj->DeviceObject);
case 5:
// KeInitializeDpc has no counterpart
case 4:
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:
PCICC32FreeResources(driverObj->DeviceObject);
default:
case 0:
RtlInitUnicodeString(&symbol_name, DOS_DEVICE_NAME);
// delete the symbolicLink in the registry
IoDeleteSymbolicLink( &symbol_name);
// delete the deviceObject
IoDeleteDevice(driverObj->DeviceObject);
}
KdPrint(("PCICC32Unload() OK.\n"));
}
//------------------------------------------------------------------------
// called at CreateFile()
NTSTATUS PCICC32Open(PDEVICE_OBJECT deviceObj, PIRP Irp)
{
NTSTATUS result = STATUS_SUCCESS;
ANSI_STRING name;
int nCC32;
int i;
DEVICE_EXT *pDevExt = (DEVICE_EXT *)(deviceObj->DeviceExtension);
PCIADA *pciada;
FILE_OBJ *file_obj;
name.Buffer = NULL;
name.MaximumLength = 80;
result = RtlUnicodeStringToAnsiString(&name, &(Irp->Tail.Overlay.OriginalFileObject->FileName), TRUE);
if (result != STATUS_SUCCESS) goto fin;
KdPrint(("PCICC32Open(%s)\n", name.Buffer));
result = InterpreteFileName(name.Buffer, &nCC32);
if (result != STATUS_SUCCESS) goto fin;
KdPrint(("PCICC32Open(%d)\n", nCC32));
RtlFreeAnsiString(&name);
file_obj = (FILE_OBJ *)ExAllocatePool(NonPagedPool, sizeof(FILE_OBJ));
if (file_obj == (FILE_OBJ *)NULL)
{
result = STATUS_NO_MEMORY;
goto fin;
}
file_obj->uwAssociatedCC32 = nCC32;
Irp->Tail.Overlay.OriginalFileObject->FsContext = (PVOID)file_obj;
result = PCICC32ScanCC32(deviceObj);
if (result != STATUS_SUCCESS) goto fin;
for (i = 0; i < pDevExt->nPCIADAs; i++)
{
pciada = &pDevExt->pciada[i];
if (pciada->wModuleNumber == nCC32)
{
pDevExt->cc32[nCC32] = pciada; // create association
pciada->dwLinkCount++;
enableCC32(pciada);
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);
return result;
}
//------------------------------------------------------------------------
// called at close()
NTSTATUS PCICC32Close(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(("PCICC32Close(%d)\n", file_obj->uwAssociatedCC32));
if (file_obj != (FILE_OBJ *)NULL)
{
pciada = pDevExt->cc32[file_obj->uwAssociatedCC32];
pciada->dwLinkCount--;
// disable interrupts when closing
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;
if (!pciada->dwLinkCount)
disableCC32(pciada);
ExFreePool(file_obj);
Irp->Tail.Overlay.OriginalFileObject->FsContext = (FILE_OBJ *)NULL;
}
KdPrint(("PCICC32Close OK\n"));
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// called at
NTSTATUS PCICC32Shutdown(PDEVICE_OBJECT deviceObj, PIRP irp)
{
KdPrint(("PCICC32Shutdown()\n"));
// deinit interfaces and interrupts
PCICC32DeInitPCIADAs(deviceObj);
KdPrint(("PCICC32Shutdown() OK\n"));
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// called at ioctl()
NTSTATUS PCICC32DeviceControl(PDEVICE_OBJECT deviceObj, PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
int nIndex;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
nIndex = CTL_INDEX(IrpStack->Parameters.DeviceIoControl.IoControlCode);
KdPrint(("PCICC32DeviceControl(%d / 0x%08x)\n", nIndex, Irp->Tail.Overlay.OriginalFileObject));
if (nIndex > CTL_INDEX(PCICC32_LAST_CTL_CODE))
{
KdPrint(("LastIndex(%d)\n", CTL_INDEX(PCICC32_LAST_CTL_CODE)));
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
KdPrint(("PCICC32DeviceControl() FAIL.\n"));
return STATUS_UNSUCCESSFUL;
}
return ioctl[nIndex](deviceObj, Irp, IrpStack);
}
//------------------------------------------------------------------------
// called at read()
static BOOLEAN PCICC32Read_kernel(PVOID pvContext)
{
register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
register ULONG i = 0;
USHORT wCntrl;
wCntrl = READ_REGISTER_USHORT(context->pciada->pwCntrl);
if (context->file_obj->wBlockTransfer & AUTOREAD)
{
wCntrl &= ~0x0004; // enable autoread - set bit to 0
WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);
}
// do the read ---
if (context->file_obj->wBlockTransfer & UNTIL_NOT_Q)
{
// read first time to get Q information
register ULONG tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address);
if (context->file_obj->wAccessType == WORD_ACCESS)
{
PUSHORT pwBuffer = (PUSHORT)context->pOutputBuffer;
PUSHORT pwBufEnd = (PUSHORT)((PUCHAR)context->pOutputBuffer + context->Length);
while ((tempBuffer & 0x80000000) && (pwBuffer < pwBufEnd))
{
*pwBuffer++ = (USHORT)tempBuffer;
tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address); // read the same address multiple times as long to get Q
i++;
}
}
else
{
// LONG_ACCESS
PULONG pdwBuffer = (PULONG)context->pOutputBuffer;
PULONG pdwBufEnd = (PULONG)((PUCHAR)context->pOutputBuffer + context->Length);
while ((tempBuffer & 0x80000000) && (pdwBuffer < pdwBufEnd))
{
*pdwBuffer++ = tempBuffer;
tempBuffer = READ_REGISTER_ULONG((ULONG *)context->Address); // read the same address multiple times as long to get Q
i++;
}
}
i *= context->file_obj->wAccessType;
KdPrint(("UNTIL_NOT_Q, 0x%08x bytes read\n", i));
}
else // no UNTIL_NOT_Q
{
while (i < context->Length)
{
context->file_obj->fRead((void *)((PUCHAR)context->pOutputBuffer + i), (void *)context->Address); // read the same address multiple times
i += context->file_obj->wAccessType;
}
}
// disable autoread unconditionally - set bit to 1
wCntrl |= 0x0004;
WRITE_REGISTER_USHORT(context->pciada->pwCntrl, wCntrl);
context->Length = i;
return TRUE;
}
NTSTATUS PCICC32Read(PDEVICE_OBJECT device_Obj, PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_EXT *pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
SYNC_CONTEXT context;
context.file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
context.pciada = pDevExt->cc32[context.file_obj->uwAssociatedCC32];
context.pOutputBuffer = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));
context.Address = IrpStack->Parameters.Read.ByteOffset.LowPart;
context.Length = 0;
KdPrint(("PCICC32Read(%d)\n", context.file_obj->uwAssociatedCC32));
if (context.Address > IFR_SPACE)
Status = STATUS_ACCESS_VIOLATION;
else
{
// do here in between what has to be done -----------------
context.Length = IrpStack->Parameters.Read.Length;
KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
context.Address = (ULONG)context.pciada->pvVirtIfr + context.Address;
KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Read_kernel, &context);
// do here in between what has to be done end -------------
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = context.Length;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
KdPrint(("PCICC32Read(), Status = 0x%08x\n", Status));
return Status;
}
//------------------------------------------------------------------------
// called at write()
static BOOLEAN PCICC32Write_kernel(PVOID pvContext)
{
register SYNC_CONTEXT *context = (SYNC_CONTEXT *)pvContext;
register ULONG i = 0;
// do the write ---
while (i < context->Length)
{
context->file_obj->fWrite((void *)context->Address, (void *)((PUCHAR)context->pInputBuffer + i)); // write the same address multiple times
i += context->file_obj->wAccessType;
}
context->Length = i;
return TRUE;
}
NTSTATUS PCICC32Write(PDEVICE_OBJECT device_Obj, PIRP Irp)
{
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
DEVICE_EXT *pDevExt = (DEVICE_EXT *)(device_Obj->DeviceExtension);
SYNC_CONTEXT context;
context.file_obj = (FILE_OBJ *)Irp->Tail.Overlay.OriginalFileObject->FsContext;
context.pciada = pDevExt->cc32[context.file_obj->uwAssociatedCC32];
context.pInputBuffer = ((void *)(MmGetSystemAddressForMdl(Irp->MdlAddress)));
context.Address = IrpStack->Parameters.Read.ByteOffset.LowPart;
context.Length = 0;
KdPrint(("PCICC32Write(%d)\n", context.file_obj->uwAssociatedCC32));
if (context.Address > IFR_SPACE)
Status = STATUS_ACCESS_VIOLATION;
else
{
register ULONG i = 0;
// do here in between what has to be done -----------------
context.Length = IrpStack->Parameters.Read.Length;
KdPrint(("Address = 0x%08x, Length = 0x%08x\n", context.Address, context.Length));
context.Address = (ULONG)context.pciada->pvVirtIfr + context.Address;
KeSynchronizeExecution(context.pciada->InterruptObject, PCICC32Write_kernel, &context);
// do here in between what has to be done end -------------
}
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = context.Length;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
KdPrint(("PCICC32Write(), Status = 0x%08x\n", Status));
return Status;
}
//------------------------------------------------------------------------
// search for pciada's
//
NTSTATUS SearchDevices(PDEVICE_OBJECT device_Obj)
{
PCI_SLOT_NUMBER SlotNumber;
PCI_COMMON_CONFIG pci_config;
PCIADA *pciada;
ULONG length;
int *found;
int i,j,k;
KdPrint(("SearchDevices()\n"));
// prepare structures ----------------------------------------
found = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
*found = 0;
for (i = 0; i < PCICC32_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;
for (j = 0; j < PCI_MAX_BUSES; j++)
{
for (i = 0; i < PCI_MAX_DEVICES; i++)
{
SlotNumber.u.bits.DeviceNumber = i;
for (k = 0; k < PCI_MAX_FUNCTION; k++)
{
SlotNumber.u.bits.FunctionNumber = k;
length = HalGetBusData( PCIConfiguration, // Bustype
j, // PCI-Busnumber
SlotNumber.u.AsULONG, // Slotnumber
(PVOID) &(pci_config), // Pointer for the PCI-Information
sizeof(PCI_COMMON_CONFIG) );
if ((pci_config.VendorID == PCICC32_VENDOR_ID) &&
(pci_config.DeviceID == PCICC32_DEVICE_ID) &&
(pci_config.u.type0.SubSystemID == PCICC32_SUBSYS_ID) &&
(pci_config.u.type0.SubVendorID == PCICC32_SUBVEN_ID) &&
(pci_config.u.type0.BaseAddresses[3]))
{
pciada = &((DEVICE_EXT*)(device_Obj->DeviceExtension))->pciada[*found];
memcpy(&pciada
->PCIDevice
, &pci_config
, sizeof(pci_config
));
pciada->Slot = SlotNumber;
pciada->Bus = j;
KdPrint(("PCIADA found @ Bus/Slot %d/%d.\n", pciada->Bus, pciada->Slot.u.AsULONG));
(*found)++;
if (*found >= PCICC32_MAX_PCIADA) return STATUS_SUCCESS;
}
}
}
}
return STATUS_SUCCESS;
}
//---------------------------------------------------------------
// function to call for bug fix of PLX9050 build in bug
//
NTSTATUS PLX9050BugFix(PDEVICE_OBJECT device_Obj)
{
DEVICE_EXT *DeviceExtension = (DEVICE_EXT*)device_Obj->DeviceExtension;
int i;
ULONG dwData;
PCIADA *pciada;
KdPrint(("PLX9050BugFix()\n"));
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 (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
pciada->Slot.u.AsULONG,
(PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[0],
0x10, 4) != 4)
return STATUS_UNSUCCESSFUL;
if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
pciada->Slot.u.AsULONG,
(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 (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
pciada->Slot.u.AsULONG,
(PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[1],
0x14, 4) != 4)
return STATUS_UNSUCCESSFUL;
if (HalSetBusDataByOffset(PCIConfiguration, pciada->Bus,
pciada->Slot.u.AsULONG,
(PVOID)&pciada->PCIDevice.u.type0.BaseAddresses[5],
0x24, 4) != 4)
return STATUS_UNSUCCESSFUL;
}
}
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// reserve resources for PCIADAs
//
NTSTATUS PCICC32ExtractResources(PCIADA *pciada, PCM_RESOURCE_LIST pList)
{
PCM_RESOURCE_LIST pResourceList;
PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
PCM_PARTIAL_RESOURCE_LIST pPartialList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
int i;
int bug = 0;
KdPrint(("PCICC32ExtractResources()\n"));
pResourceList = pList;
pFullDescriptor = pResourceList->List;
pPartialList = &pFullDescriptor->PartialResourceList;
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(("Irq : Irql: %d, Vector: %d, Affinity: %d\n",
pciada->Irql, pciada->Vector, pciada->Affinity));
break;
case CmResourceTypeDma:
KdPrint(("Dma : \n"));
break;
case CmResourceTypePort:
KdPrint(("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 (i == 0)
{
pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
if (pciada->pvPhysLcr.LowPart & 0x80)
bug = 1;
}
}
else
{
if (i == 3)
pciada->pvPhysLcr = pPartialDescriptor->u.Memory.Start;
}
if (i == 2)
pciada->pvPhysIfr = pPartialDescriptor->u.Memory.Start;
KdPrint(("Memory : 0x%p\n", (PUCHAR)pPartialDescriptor->u.Memory.Start.LowPart));
break;
}
}
if (pciada->Irql == 0)
return STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT;
KdPrint(("PCICC32ExtractResources() OK.\n"));
return STATUS_SUCCESS;
}
NTSTATUS PCICC32ReserveResources(PDEVICE_OBJECT device_Obj)
{
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(("PCICC32ReserveResources()\n"));
// prepare resource claiming
RtlInitUnicodeString(&DriverClassName, L"PCICC32");
// 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);
if (result != STATUS_SUCCESS)
break;
result = PCICC32ExtractResources(pciada, pList);
if (result != STATUS_SUCCESS)
break;
}
// its my part to free allocated resources
ExFreePool(pList);
KdPrint(("PCICC32ReserveResources(0x%08x)\n", result));
return result;
};
//------------------------------------------------------------------------
// free resources from PCIADAs
//
NTSTATUS PCICC32FreeResources(PDEVICE_OBJECT device_Obj)
{
CM_RESOURCE_LIST ResList;
BOOLEAN bConflict;
UNICODE_STRING DriverClassName;
KdPrint(("PCICC32FreeResources()\n"));
RtlInitUnicodeString(&DriverClassName, L"PCICC32");
ResList.Count = 0;
IoReportResourceUsage(&DriverClassName, device_Obj->DriverObject,
&ResList, sizeof(ResList), device_Obj,
NULL, 0, FALSE, &bConflict);
return STATUS_SUCCESS;
};
//------------------------------------------------------------------------
// translate memory resources to neutral for PCIADAs
//
NTSTATUS PCICC32TranslateBusAddresses(PDEVICE_OBJECT device_Obj)
{
int i;
NTSTATUS result = STATUS_SUCCESS;
int nPCIADAs = ((DEVICE_EXT*)(device_Obj->DeviceExtension))->nPCIADAs;
ULONG memType0, memType2;
PCIADA *pciada;
KdPrint(("TranslateBusAddresseses()\n"));
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;
}
if ((memType0) || (memType2))
{
result = STATUS_UNSUCCESSFUL;
break;
}
}
return result;
}
//------------------------------------------------------------------------
// map address spaces to virtual addresses
//
NTSTATUS PCICC32MapIOspaces(PDEVICE_OBJECT device_Obj)
{
int i;
DEVICE_EXT *pDevExt = (DEVICE_EXT*)device_Obj->DeviceExtension;
int nPCIADAs = pDevExt->nPCIADAs;
PCIADA *pciada;
KdPrint(("PCICC32MapIOspaces()\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;
DEVICE_EXT *pDevExt = (DEVICE_EXT*)(device_object->DeviceExtension);
int nPCIADAs = pDevExt->nPCIADAs;
PCIADA *pciada;
KdPrint(("InitializeCustomDPCObject()\n"));
for (i = 0; i < nPCIADAs; i++)
{
pciada = &pDevExt->pciada[i];
KeInitializeDpc(&pciada->kDPCobj, fMyDefferedRoutine, (PVOID)device_object);
}
return STATUS_SUCCESS;
}
//------------------------------------------------------------------------
// init structures a.s.o.
//
VOID PCICC32SoftInit(PDEVICE_OBJECT device_Obj)
{
int i;
PCIADA *pciada;
for (i = 0; i < PCICC32_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->wModuleNumber = 0xFFFF;
pciada->wFPGAVersion = 0xFFFF;
pciada->wModuleType = 1; // always CC32
pciada->InterruptObject = NULL;
pciada->Irql = 0;
pciada->Vector = 0;
pciada->Affinity = 0;
pciada->dwLinkCount = 0;
pciada->dwIrqStatus = 0;
pciada->pBlockingIrp = (PIRP *)NULL;
pciada->pIrqControlFile = (FILE_OBJ *)NULL;
}
// no CC32 associated to any PCIADA
for (i = 0; i < PCICC32_MAX_CC32; i++)
((DEVICE_EXT*)(device_Obj->DeviceExtension))->cc32[i] = NULL;
}
//------------------------------------------------------------------------
// the ultimate starting point of a driver
NTSTATUS DriverEntry(PDRIVER_OBJECT driverObj, PUNICODE_STRING regPath)
{
int i;
PDEVICE_OBJECT device_object; // pointer to the device object
UNICODE_STRING device_name;
UNICODE_STRING symbol_name;
NTSTATUS result = STATUS_SUCCESS;
PCIADA *pciada; // pointer to a PCIADA
int nPCIADAs; // count of PCIADAs
DEVICE_EXT *DeviceExtension = NULL;
KdPrint(("DriverEntry() ----%d.%d-------------------------\n", (DRIVER_VERSION >> 16) & 0xFFFF, DRIVER_VERSION & 0xFFFF));
driverObj->DriverUnload = PCICC32Unload;
driverObj->MajorFunction[IRP_MJ_CREATE] = PCICC32Open;
driverObj->MajorFunction[IRP_MJ_CLOSE] = PCICC32Close;
driverObj->MajorFunction[IRP_MJ_READ] = PCICC32Read;
driverObj->MajorFunction[IRP_MJ_WRITE] = PCICC32Write;
driverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PCICC32DeviceControl;
driverObj->MajorFunction[IRP_MJ_SHUTDOWN] = PCICC32Shutdown;
RtlInitUnicodeString(&device_name, L"\\Device\\CC32");
/* 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;
// 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->nInitState = 0;
// init pciada structures ------------------------------------
PCICC32SoftInit(device_object);
// search for PCIADAs ----------------------------------------
result = SearchDevices(device_object);
nPCIADAs = DeviceExtension->nPCIADAs;
if ((result != STATUS_SUCCESS) || !(nPCIADAs))
{
PCICC32Unload(driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
// request exclusive ownership of .. ---------------------------------
if ((result = PCICC32ReserveResources(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return result;
}
else
DeviceExtension->nInitState++;
// fix PLX9050 Bug -------------------------------------------
if ((result = PLX9050BugFix(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return result;
}
// translate BUS relative addresses ----------------------------------
if ((result = PCICC32TranslateBusAddresses(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
// translate Interrupt Resources used --------------------------------
if ((result = PCICC32TranslateInterrupt(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
// map address spaces to virtual addresses ---------------------------
if ((result = PCICC32MapIOspaces(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
// initialze my custom DPC objects -----------------------------------
if ((result = InitializeCustomDPCObjects(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return result;
}
else
DeviceExtension->nInitState++;
// disable all interrupts --------------------------------------------
for (i = 0; i < nPCIADAs; i++)
{
pciada = &DeviceExtension->pciada[i];
globalInterruptDisable(pciada);
}
// connect interrupts to service routines ----------------------------
if ((result = PCICC32ConnectInterrupt(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
else
DeviceExtension->nInitState++;
// scan all connected CC32 for info and later use -------------------
if ((result = PCICC32ScanCC32(device_object)) != STATUS_SUCCESS)
{
PCICC32Unload(driverObj);
return STATUS_DEVICE_DOES_NOT_EXIST;
}
device_object->Flags &= ~DO_DEVICE_INITIALIZING;
KdPrint(("DriverEntry() OK.\n"));
return result;
}