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