📄 driverwi.c
字号:
//-----------------------------------------------------------------------------
// $Id: driverwinnt.c,v 1.0.0 2004/01/13
//-----------------------------------------------------------------------------
//
// ProfiM - PROFIBUS MASTER DRIVER FOR WINDOWS NT/2000
//
// Author:
// Pavel Trnka, CTU FEE
// trnkap@seznam.cz
// With help and advices from:
// Ing. Petr Smolik, CTU FEE
// Ing. Pavel Pisa, CTU FEE
// Ing. Pavel Burget, CTU FEE
//
//-----------------------------------------------------------------------------
//
// Popis:
// ------
// Cast ovladace, ktera je do projektu vkladana pokud ovladac neni prekladan
// s podporou PnP - falesne makro PnP (vardef.h) neni nadefinovano. Prelozeny
// ovladac je tak urcen do prostredi Windows NT.
// Zajistuje start ovladace vytvorenim vstupni bodu DriverEntry a ukoncovani
// jeho cinnosti (UnloadDriver).
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//---------------------------------------------------------------------------
// DriverEntry
//
// Description:
// NT device Driver Entry point
//
// Arguments:
// DriverObject - Pointer to this device's driver object
// RegistryPath - Pointer to the Unicode regsitry path name
//
// Return Value:
// NTSTATUS
//
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath )
{
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS status, ioConnectStatus;
UNICODE_STRING uniNtNameString;
UNICODE_STRING uniWin32NameString;
KIRQL irql = DEF_IRQ_LINE;
KAFFINITY Affinity;
ULONG MappedVector, AddressSpace = 1;
PPROFIM_DEVICE_EXTENSION extension;
BOOLEAN ResourceConflict;
PHYSICAL_ADDRESS InPortAddr, OutPortAddr;
RS_DbgPrint( "ProfiM: Enter the driver!\n" );
DbgPrint ("ProfiM: Version 0.025 (%s %s)\n",__TIME__,__DATE__);
//
// Create counted string version of our device name.
//
RtlInitUnicodeString( &uniNtNameString, NT_DEVICE_NAME );
//
// Create the device object, single-thread access (TRUE)
//
status = IoCreateDevice( DriverObject,
sizeof( PROFIM_DEVICE_EXTENSION ),
&uniNtNameString,
FILE_DEVICE_UNKNOWN,
0,
TRUE,
&deviceObject );
if ( !NT_SUCCESS( status ) )
{
RS_DbgPrint( "ProfiM: IoCreateDevice failed\n" );
return status;
}
extension = ( PPROFIM_DEVICE_EXTENSION ) deviceObject->DeviceExtension;
//
// Initialize structure control identificator
//
extension->magic = PROFIM_MAGIC;
extension->PB.AllInitialized = FALSE;
extension->ContinueFrame = FALSE;
//
// Set the FLAGS field
//
deviceObject->Flags |= DO_BUFFERED_IO;
//
// Get the configuration information from the Registry
//
status = GetConfiguration( deviceObject->DeviceExtension, RegistryPath );
if ( !NT_SUCCESS( status ) )
{
RS_DbgPrint( "ProfiM: GetConfiguration failed\n" );
return status;
}
//
// This call will map our IRQ to a system vector. It will also fill
// in the IRQL (the kernel-defined level at which our ISR will run),
// and affinity mask (which processors our ISR can run on).
//
// We need to do this so that when we connect to the interrupt, we
// can supply the kernel with this information.
//
MappedVector = HalGetInterruptVector( Isa, // Interface type
0, // Bus number
extension->IRQLine, extension->IRQLine, &irql, // IRQ level
& Affinity // Affinity mask
);
//
// A little known Windows NT fact,
// If MappedVector==0, then HalGetInterruptVector failed.
//
if ( MappedVector == 0 )
{
RS_DbgPrint( "ProfiM: HalGetInterruptVector failed\n" );
return ( STATUS_INVALID_PARAMETER );
}
//
// Save off the Irql
//
extension->Irql = irql;
//
// Translate the base port address to a system mapped address.
// This will be saved in the device extension after IoCreateDevice,
// because we use the translated port address to access the ports.
//
InPortAddr.LowPart = ( ULONG ) extension->PortAddress;
InPortAddr.HighPart = 0;
if ( !HalTranslateBusAddress( Isa,
0,
InPortAddr,
&AddressSpace,
&OutPortAddr ) )
{
RS_DbgPrint( "ProfiM: HalTranslateBusAddress failed\n" );
return STATUS_SOME_NOT_MAPPED;
}
if ( NT_SUCCESS( status ) )
{
//
// Create dispatch points for create/open, close, unload, and ioctl
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchRoutine;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRoutine;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchRoutine;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine;
DriverObject->DriverUnload = UnloadDriver;
//
// check if resources (ports and interrupt) are available
//
ReportUsage( DriverObject, deviceObject, OutPortAddr, &ResourceConflict );
if ( ResourceConflict )
{
RS_DbgPrint( "ProfiM: Couldn't get resources\n" );
IoDeleteDevice( deviceObject );
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// fill in the device extension
//
extension = ( PPROFIM_DEVICE_EXTENSION ) deviceObject->DeviceExtension;
extension->DeviceObject = deviceObject;
extension->PortAddress = ( PVOID ) OutPortAddr.LowPart;
KeInitializeDpc(&extension->CompleteDPC, ProfiM_CompleteDPC, extension);
KeInitializeSpinLock( &(extension->InterruptSpinLock) );
//
// connect the device driver to the IRQ
//
ioConnectStatus = IoConnectInterrupt( &extension->InterruptObject,
ProfiM_Isr,
extension->DeviceObject,
&(extension->InterruptSpinLock),
MappedVector,
irql,
irql,
Latched,
FALSE,
Affinity,
FALSE );
if ( !NT_SUCCESS( ioConnectStatus ) )
{
RS_DbgPrint( "ProfiM: Couldn't connect interrupt\n" );
IoDeleteDevice( deviceObject );
return ioConnectStatus;
}
RS_DbgPrint( "ProfiM: just about ready!\n" );
//
// Create counted string version of our Win32 device name.
//
RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
//
// Create a link from our device name to a name in the Win32 namespace.
//
status = IoCreateSymbolicLink( &uniWin32NameString, &uniNtNameString );
if ( !NT_SUCCESS( status ) )
{
RS_DbgPrint( "ProfiM: Couldn't create the symbolic link\n" );
IoDeleteDevice( DriverObject->DeviceObject );
}
else
{
//
// Setup the Dpc for ISR routine
//
IoInitializeDpcRequest( DriverObject->DeviceObject, ProfiM_Dpc_Routine );
//
// Initialize the device (enable IRQ's, hit the hardware)
//
Initialize_ProfiM( extension, 0 );
/// Nastaveni priznaku vysilani
extension->Sending = FALSE;
// priznak k vymazani vsech casovacich znaku ze zacatku vysilaci fronty
extension->FlushTCH = FALSE;
// umozni rozbeh ovladace nez se aktivuje hlidaci rutina watchdogu
extension->WatchDogTrigger = 0;
extension->HIDCounter = 1;
#ifdef PISA_IO
extension->ModemInterruptState = MI_Disabled;
#endif
RS_DbgPrint( "ProfiM: All initialized!\n" );
PB_Init( &( extension->PB ), extension, RegistryPath );
}
}
else
{
RS_DbgPrint( "ProfiM: Couldn't create the device\n" );
}
return status;
}
//---------------------------------------------------------------------------
// UnloadDriver
//
// Description:
// Free all the allocated resources, etc.
//
// Arguments:
// DriverObject - pointer to a driver object
//
// Return Value:
// None
//
VOID UnloadDriver( IN PDRIVER_OBJECT DriverObject )
{
WCHAR deviceLinkBuffer[] = L"\\DosDevices\\ProfiM";
UNICODE_STRING deviceLinkUnicodeString;
PPROFIM_DEVICE_EXTENSION extension;
extension = DriverObject->DeviceObject->DeviceExtension;
PB_Close( &( extension->PB ) );
//
// Deactivate all of the MCR interrupt sources.
//
WRITE_PORT_UCHAR( extension->ComPort.MCR, MCR_DEACTIVATE_ALL );
//
// Free any resources
//
IoDisconnectInterrupt( extension->InterruptObject );
//
// Delete the symbolic link
//
RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
IoDeleteSymbolicLink( &deviceLinkUnicodeString );
//
// Delete the device object
//
IoDeleteDevice( DriverObject->DeviceObject );
RS_DbgPrint( "ProfiM: Unloaded\n" );
return;
}
//---------------------------------------------------------------------------
// ReportUsage
//
// Description:
// This routine registers (reports) the I/O and IRQ usage for this driver.
//
// Arguments:
// DriverObject - Pointer to the driver object
// DeviceObject - Pointer to the Device object
// PortAddress - Address of I/O port used
// ConflictDetected - TRUE if a resource conflict was detected.
//
// Return Value:
// TRUE - If a Resource conflict was detected
// FALSE - If no conflict was detected
//
BOOLEAN ReportUsage( IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT DeviceObject,
IN PHYSICAL_ADDRESS PortAddress,
IN BOOLEAN *ConflictDetected )
{
PPROFIM_DEVICE_EXTENSION extension;
ULONG sizeOfResourceList;
PCM_RESOURCE_LIST resourceList;
PCM_FULL_RESOURCE_DESCRIPTOR nextFrd;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;
extension = ( PPROFIM_DEVICE_EXTENSION ) DeviceObject->DeviceExtension;
//
// The size of the resource list is going to be one full descriptor
// which already has one partial descriptor included, plus another
// partial descriptor. One partial descriptor will be for the
// interrupt, and the other for the port addresses.
//
sizeOfResourceList = sizeof( CM_FULL_RESOURCE_DESCRIPTOR );
//
// The full resource descriptor already contains one
// partial. Make room for one more.
//
// It will hold the irq "prd", and the port "prd".
// ("prd" = partial resource descriptor)
//
sizeOfResourceList += sizeof( CM_PARTIAL_RESOURCE_DESCRIPTOR );
//
// Now we increment the length of the resource list by field offset
// of the first frd. This will give us the length of what preceeds
// the first frd in the resource list.
// (frd = full resource descriptor)
//
sizeOfResourceList += FIELD_OFFSET( CM_RESOURCE_LIST, List[0] );
resourceList = ExAllocatePool( PagedPool, sizeOfResourceList );
if ( !resourceList )
{
return FALSE;
}
//
// Zero out the list
//
RtlZeroMemory( resourceList, sizeOfResourceList );
resourceList->Count = 1;
nextFrd = &resourceList->List[0];
nextFrd->InterfaceType = Isa;
nextFrd->BusNumber = 0;
//
// We are going to report port addresses and interrupt
//
nextFrd->PartialResourceList.Count = 2;
//
// Now fill in the port data. We don't wish to share
// this port range with anyone.
//
// Note: the port address we pass in is the one we got
// back from HalTranslateBusAddress.
//
partial = &nextFrd->PartialResourceList.PartialDescriptors[0];
partial->Type = CmResourceTypePort;
partial->ShareDisposition = CmResourceShareDriverExclusive;
partial->Flags = CM_RESOURCE_PORT_IO;
partial->u.Port.Start = PortAddress;
partial->u.Port.Length = DEF_PORT_RANGE;
partial++;
//
// Now fill in the irq stuff.
//
// Note: for IoReportResourceUsage, the Interrupt.Level and
// Interrupt.Vector are bus-specific level and vector, just
// as we passed in to HalGetInterruptVector, not the mapped
// system vector we got back from HalGetInterruptVector.
//
partial->Type = CmResourceTypeInterrupt;
partial->u.Interrupt.Level = extension->IRQLine;
partial->u.Interrupt.Vector = extension->IRQLine;
partial->ShareDisposition = CmResourceShareDriverExclusive;
partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
IoReportResourceUsage( NULL,
DriverObject,
resourceList,
sizeOfResourceList,
NULL,
NULL,
0,
FALSE,
ConflictDetected );
//
// The above routine sets the BOOLEAN parameter ConflictDetected
// to TRUE if a conflict was detected.
//
ExFreePool( resourceList );
return ( *ConflictDetected );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -