📄 driverpn.c
字号:
//-----------------------------------------------------------------------------
// $Id: driverpnp.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 pro preklad s podporou PnP. Do projektu je vkladana pokud
// je nadefinovano falesne makro PnP (vardef.h).
// Zajistuje start ovladace (DriverEntry), ziskani hardwarovych prostredku
// (AddDevice), zpracovavani PnP zprav (DispatchPnP) a vsechny potrebne funkce
// pro zajisteni PnP kompatibilitu ovladace.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#include "DriverPnP.h"
///////////////////////////////////////////////////////////////////////////////
//
// Unicode String Manipulation routine
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS MyAllocUnicodeString( PUNICODE_STRING UStr,
PUNICODE_STRING InUStr,
USHORT Len )
{
NTSTATUS Status;
ULONG Size;
if ( !Len && InUStr )
{
Len = InUStr->Length;
}
RtlInitUnicodeString( UStr, NULL );
if ( Len )
{
Size = Len + 2;
UStr->Buffer = ExAllocatePool( PagedPool, Size );
if ( !UStr->Buffer )
return STATUS_UNSUCCESSFUL;
RtlZeroMemory( UStr->Buffer, Size );
UStr->MaximumLength = Len;
if ( InUStr )
RtlCopyUnicodeString( UStr, InUStr );
}
return STATUS_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetRegistryDWord
//
// Reads a registry key value from an already opened registry key
//
// INPUTS:
// Handle - handle to the opened registry key
// KeyNameString - WCHAR string to the desired key
// OUTPUTS:
// Data - buffer for the data
//
// RETURNS:
// NT Status code
//
// IRQL:
// IRQL PASSIVE_LEVEL
//
///////////////////////////////////////////////////////////////////////////////
BOOLEAN
GetRegistryDWord (
IN HANDLE Handle,
IN PWCHAR KeyNameString,
IN PULONG Data
)
{
UNICODE_STRING keyName;
ULONG length;
PKEY_VALUE_FULL_INFORMATION fullInfo;
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
ULONG DataLength=4;
RtlInitUnicodeString (&keyName, KeyNameString);
length = sizeof(KEY_VALUE_FULL_INFORMATION)+keyName.Length+4+DataLength;
fullInfo = ExAllocatePool(PagedPool, length);
if (fullInfo)
{
status = ZwQueryValueKey (Handle,&keyName,KeyValueFullInformation,
fullInfo,length,&length);
if (NT_SUCCESS(status))
{
// If there is enough room in the data buffer, copy the output
if ( DataLength >= fullInfo->DataLength )
{
RtlCopyMemory (Data,((PUCHAR) fullInfo) + fullInfo->DataOffset,
fullInfo->DataLength);
ExFreePool(fullInfo);
return TRUE;
}
}
ExFreePool(fullInfo);
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// PCI routines
//
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#define PCI_ANY_ID 0xffff
typedef struct pci_device_id {
USHORT vendor;
USHORT device;
USHORT subvendor;
USHORT subdevice;
USHORT class_val,clask_mask;
ULONG driver_data;
} pci_device_id_t;
//-----------------------------------------------------------------------------
static struct pci_device_id pb_pci_tbl[] /*__devinitdata*/ = {
/* Advantech PCI-1602A, negated DTR */
{ /* PCI_VENDOR_ID */ 0x13fe, /* PCI_DEVICE_ID */ 0x1600,
/* PCI_VENDOR_ID */ PCI_ANY_ID, /* PCI_SUBDEVICE_ID */ PCI_ANY_ID,
0, 0, 0x16954000|U950PCI_CHOPT_TXDTRNEG|U950PCI_CHOPT_HSPDOSC},
/* Tedia PCI-1482 */
{ /* PCI_VENDOR_ID */ 0x1415, /* PCI_DEVICE_ID */ 0x950A,
/* PCI_VENDOR_ID */ PCI_ANY_ID, /* PCI_SUBDEVICE_ID */ PCI_ANY_ID,
0, 0, 0x16954000|U950PCI_CHOPT_RXDONRI|U950PCI_CHOPT_HSPDOSC},
/* Tedia PCI-1482 with PiKRON signature */
{ /* PCI_VENDOR_ID */ 0x1760, /* PCI_DEVICE_ID */ 0x8004,
/* PCI_VENDOR_ID */ PCI_ANY_ID, /* PCI_SUBDEVICE_ID */ PCI_ANY_ID,
0, 0, 0x16954000|U950PCI_CHOPT_RXDONRI},
{ 0, } /* terminate list */
};
//-----------------------------------------------------------------------------
BOOLEAN FindPciHWID(PWCHAR HWID,
OUT pci_device_id_t **Ppci_device_id
)
{
PWCHAR pwcH, pwcM;
WCHAR fldName;
USHORT vendorID=0;
USHORT deviceID=0;
USHORT subvendorID=0;
USHORT subdeviceID=0;
ULONG val, i, c;
static WCHAR PciHWIDMask[]=L"PCI\\VEN_vvvv&DEV_xxxx&SUBSYS_sssswwww";
pci_device_id_t *device_id;
*Ppci_device_id=NULL;
if(HWID==NULL) return FALSE;
pwcH=HWID;
pwcM=PciHWIDMask;
while(*pwcH&&*pwcM) {
if(*pwcH==*pwcM){
pwcH++; pwcM++;
continue;
}
fldName=*pwcM;
if((fldName!='v')&&(fldName!='x')&&
(fldName!='s')&&(fldName!='w')) break;
val=0;
for(i=4;i--;){
c=*(pwcH++); pwcM++;
if(c<='9') c-='0';
else if(c<='F') c=c-'A'+10;
else if(c<='f') c=c-'a'+10;
if(c>15) {val=0;break;}
val<<=4;
val+=c;
}
switch (fldName) {
case 'v':
vendorID=(USHORT)val;
break;
case 'x':
deviceID=(USHORT)val;
break;
case 'w':
subvendorID=(USHORT)val;
break;
case 's':
subdeviceID=(USHORT)val;
break;
}
}
#if DBG
DbgPrint("PB: Ven %04X Dev %04X SubVen %04X SubDev %04X\n",
vendorID,deviceID,subvendorID,subdeviceID);
#endif
for(device_id=pb_pci_tbl;device_id->vendor;device_id++){
if((device_id->vendor!=PCI_ANY_ID)&&(device_id->vendor!=vendorID)) continue;
if((device_id->device!=PCI_ANY_ID)&&(device_id->device!=deviceID)) continue;
if((device_id->subvendor!=PCI_ANY_ID)&&(device_id->vendor!=subvendorID)) continue;
if((device_id->subdevice!=PCI_ANY_ID)&&(device_id->device!=subdeviceID)) continue;
*Ppci_device_id=device_id;
return TRUE;
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// DriverEntry
//
// This routine is called when the driver is first loaded.
//
// INPUTS:
//
// DriverObj - Address of the DRIVER_OBJECT created by NT for this driver.
//
// RegistryPath - UNICODE_STRING which represents this drivers KEY in the
// Registry.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// STATUS_SUCCESS. Otherwise an error indicating why the driver could not
// Load.
//
// IRQL:
//
// This routine is called at IRQL_PASSIVE_LEVEL.
//
// NOTES:
//
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath )
{
DbgPrint( "ProfiM PnP: Enter the driver!\n" );
DbgPrint( "ProfiM PnP: Version 0.025 with PnP support (%s %s)\n",
__TIME__,
__DATE__ );
DbgPrint( "ProfiM PnP: Umisteni v registrech: \"%ws\" ",
RegistryPath->Buffer );
//
// Establish dispatch entry points for the functions we support
//
DriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine;
DriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchRoutine;
DriverObj->MajorFunction[IRP_MJ_READ] = DispatchRoutine;
DriverObj->MajorFunction[IRP_MJ_WRITE] = DispatchRoutine;
DriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine;
DriverObj->MajorFunction[IRP_MJ_CLEANUP] = DispatchRoutine;
//
// PnP and Power entry points
//
DriverObj->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
/// DriverObj->MajorFunction[IRP_MJ_POWER] = DispatchPower;
//
// WMI entry point
//
DriverObj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchSystemControl;
//
// AddDevice Function
//
DriverObj->DriverExtension->AddDevice = AddDevice;
//
// Unload function
//
DriverObj->DriverUnload = UnloadDriver;
//
// Save the registry path for later use.
//
MyAllocUnicodeString( &PB_RegistryPath, RegistryPath, 0 );
//
// Initial reasonable value for driver spinlock
//
//** uL_SpinLock_Irql=DISPATCH_LEVEL+1;
DbgPrint( "ProfiM PnP: All initialized!\n" );
return( STATUS_SUCCESS );
}
///////////////////////////////////////////////////////////////////////////////
//
// DriverUnload
//
// This routine is our dynamic unload entry point. We are called here when
// the OS wants to unload our driver. It is our responsibility to release any
// resources we allocated.
//
// INPUTS:
//
// DriverObj - Address of our DRIVER_OBJECT.
//
// OUTPUTS:
//
// None.
//
// RETURNS:
//
// None.
//
// IRQL:
//
// This routine is called at IRQL_PASSIVE_LEVEL.
//
// NOTES:
//
// No doubt we pool leak at this entry point by not properly returning everything.
//
///////////////////////////////////////////////////////////////////////////////
VOID UnloadDriver( PDRIVER_OBJECT DriverObject )
{
PPROFIM_DEVICE_EXTENSION devExt;
PDEVICE_OBJECT devObj, nextDevObj;
IO_RESOURCE_REQUIREMENTS_LIST reqList;
NTSTATUS code;
UNICODE_STRING linkName;
CM_RESOURCE_LIST returnResources;
BOOLEAN conflictDetected;
DbgPrint( "ProfiM PnP: DriverUnload\n" );
//
// For THIS driver, there will only ever be a single device object.
// Because of this, we just get it from the DriverObj. If this were
// a multiple device driver, we would do this in a while loop...
//
nextDevObj = DriverObject->DeviceObject;
while ( nextDevObj )
{
devObj = nextDevObj;
nextDevObj = devObj->NextDevice;
// Find ProfiM Device Extension
devExt = ( PPROFIM_DEVICE_EXTENSION ) devObj->DeviceExtension;
if ( !devExt )
{
DbgPrint( "PnP: UnloadDriver Error - DeviceExtension is NULL!" );
return;
}
if ( devExt->magic != PROFIM_MAGIC )
{
DbgPrint( "PnP: UnloadDriver Error - Device Extension MAGIC is invalid!" );
return;
}
// Set State
devExt->State = STATE_REMOVED;
// Return ProfiM system resources
ReturnResources( devExt );
// Destroy DeviceObject
RemoveDevice( devObj );
}
if ( PB_RegistryPath.Buffer )
ExFreePool( PB_RegistryPath.Buffer );
}
VOID PrintState( PPROFIM_DEVICE_EXTENSION devExt );
VOID RequestIncrement( PPROFIM_DEVICE_EXTENSION devExt );
VOID RequestDecrement( PPROFIM_DEVICE_EXTENSION devExt );
VOID WaitForStop( PPROFIM_DEVICE_EXTENSION devExt );
VOID WaitForRemove( PPROFIM_DEVICE_EXTENSION devExt );
VOID ClearQueues( PPROFIM_DEVICE_EXTENSION devExt )
{
/*stub*/
};
VOID ProcessQueuedRequests( PPROFIM_DEVICE_EXTENSION devExt )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -