www.pudn.com > Windows 2000设备驱动程序设计指南 .zip > Driver.cpp
//
// Driver.c - Chapter 13 - WMI Support Driver Example
//
// Copyright (C) 2000 by Jerry Lozano
//
#include "Driver.h"
// Forward declarations
//
NTSTATUS AddDevice (
IN PDRIVER_OBJECT pDriverObject,
IN PDEVICE_OBJECT pdo );
NTSTATUS DispPnp( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp );
NTSTATUS PassDownPnP( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp );
NTSTATUS HandleStartDevice( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp );
NTSTATUS HandleStopDevice( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp );
NTSTATUS HandleRemoveDevice(IN PDEVICE_OBJECT pDO,
IN PIRP pIrp );
static VOID DriverUnload (
IN PDRIVER_OBJECT pDriverObject );
static NTSTATUS DispatchCreate (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp );
static NTSTATUS DispatchClose (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp );
static NTSTATUS DispatchWrite (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp );
static NTSTATUS DispatchRead (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp );
static NTSTATUS DispatchWMI (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp );
VOID DispatchCancel (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp );
static BOOLEAN TransmitByte(
IN PVOID pArg );
VOID StartIo(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp
);
VOID PollingTimerDpc( IN PKDPC pDpc,
IN PVOID pContext,
IN PVOID SysArg1,
IN PVOID SysArg2 );
NTSTATUS
DpWmiQueryReginfo(
IN PDEVICE_OBJECT DeviceObject,
OUT PULONG RegFlags,
OUT PUNICODE_STRING InstanceName,
OUT PUNICODE_STRING *RegistryPath,
OUT PUNICODE_STRING MofResourceName,
OUT PDEVICE_OBJECT *Pdo
);
NTSTATUS
DpWmiQueryDataBlock(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG InstanceCount,
IN OUT PULONG InstanceLengthArray,
IN ULONG BufferAvail,
OUT PUCHAR Buffer
);
//++
// Function: DriverEntry
//
// Description:
// Initializes the driver.
//
// Arguments:
// pDriverObject - Passed from I/O Manager
// pRegistryPath - UNICODE_STRING pointer to
// registry info (service key)
// for this driver
//
// Return value:
// NTSTATUS signaling success or failure
//--
static UNICODE_STRING regPath;
extern "C" NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegistryPath ) {
#if DBG>=2
DbgPrint("WMIEX: DriverEntry\n");
#endif
ULONG ulDeviceNumber = 0;
NTSTATUS status = STATUS_SUCCESS;
// Announce other driver entry points
pDriverObject->DriverUnload = DriverUnload;
// Announce the WMI request entry point
pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] =
DispatchWMI;
// Announce the PNP AddDevice entry point
pDriverObject->DriverExtension->AddDevice =
AddDevice;
// Announce the PNP Major Function entry point
pDriverObject->MajorFunction[IRP_MJ_PNP] =
DispPnp;
// This includes Dispatch routines for Create, Write & Read
pDriverObject->MajorFunction[IRP_MJ_CREATE] =
DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] =
DispatchClose;
pDriverObject->MajorFunction[IRP_MJ_WRITE] =
DispatchWrite;
pDriverObject->MajorFunction[IRP_MJ_READ] =
DispatchRead;
pDriverObject->DriverStartIo = StartIo;
// Save the registry key service name for this driver
regPath = *pRegistryPath;
// Notice that no device objects are created by DriverEntry.
// Instead, we await the PnP call to AddDevice
return status;
}
//++
// Function: AddDevice
//
// Description:
// Called by the PNP Manager when a new device is
// detected on a bus. The responsibilities include
// creating an FDO, device name, and symbolic link.
//
// Arguments:
// pDriverObject - Passed from PNP Manager
// pdo - pointer to Physcial Device Object
// passed from PNP Manager
//
// Return value:
// NTSTATUS signaling success or failure
//--
NTSTATUS AddDevice (
IN PDRIVER_OBJECT pDriverObject,
IN PDEVICE_OBJECT pdo ) {
NTSTATUS status;
PDEVICE_OBJECT pfdo;
PDEVICE_EXTENSION pDevExt;
static int ulDeviceNumber = 0;
#if DBG>=1
DbgPrint("WMIEX: AddDevice; current DeviceNumber = %d\n",
ulDeviceNumber);
#endif
// Form the internal Device Name
CUString devName("\\Device\\WMIEXAMPLE"); // for WMI Example dev
devName += CUString(ulDeviceNumber);
// Now create the device
status =
IoCreateDevice( pDriverObject,
sizeof(DEVICE_EXTENSION),
&(UNICODE_STRING)devName,
FILE_DEVICE_UNKNOWN,
0, FALSE,
&pfdo );
if (!NT_SUCCESS(status))
return status;
// Choose to use BUFFERED_IO
pfdo->Flags |= DO_BUFFERED_IO;
// Initialize the Device Extension
pDevExt = (PDEVICE_EXTENSION)pfdo->DeviceExtension;
pDevExt->pDevice = pfdo; // back pointer
pDevExt->DeviceNumber = ulDeviceNumber;
pDevExt->ustrDeviceName = devName;
pDevExt->state = Stopped;
// Initialize the MOF data
pDevExt->mofData.totalTransfers =
pDevExt->mofData.totalReads =
pDevExt->mofData.totalWrites = 0;
// Pile this new fdo on top of the existing lower stack
pDevExt->pLowerDevice = // downward pointer
IoAttachDeviceToDeviceStack( pfdo, pdo);
// Save the PDO in the device extension
pDevExt->pPDO = pdo;
// This is where the upper pointer would be initialized.
// Notice how the cast of the lower device's extension
// must be known in order to find the offset pUpperDevice.
// PLOWER_DEVEXT pLowerDevExt = (PLOWER_DEVEXT)
// pDevExt->pLowerDevice->DeviceExtension;
// pLowerDevExt->pUpperDevice = pfdo;
// Calculate the polling interval in uS
// and keep as relative time (negative value)
pDevExt->pollingInterval =
RtlConvertLongToLargeInteger( POLLING_INTERVAL * -10 );
// Prepare the polling timer and DPC
KeInitializeTimer( &pDevExt->pollingTimer );
// Notice that the DPC routine receives the fdo
// as its argument
KeInitializeDpc( &pDevExt->pollingDPC,
PollingTimerDpc,
(PVOID) pfdo );
// Form the symbolic link name
CUString symLinkName("\\??\\WMIEX");
symLinkName += CUString(ulDeviceNumber+1); // 1 based
pDevExt->ustrSymLinkName = symLinkName;
// Now create the link name
status =
IoCreateSymbolicLink( &(UNICODE_STRING)symLinkName,
&(UNICODE_STRING)devName );
if (!NT_SUCCESS(status)) {
// if it fails now, must delete Device object
IoDeleteDevice( pfdo );
return status;
}
// Clear the Device Initializing bit since the FDO was created
// outside of DriverEntry.
pfdo->Flags &= ~DO_DEVICE_INITIALIZING;
// Made it
ulDeviceNumber++;
return STATUS_SUCCESS;
}
NTSTATUS DispPnp( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp ) {
// obtain current IRP stack location
PIO_STACK_LOCATION pIrpStack;
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
#if DBG>=1
DbgPrint("WMIEX: Received PNP IRP: %d\n",
pIrpStack->MinorFunction);
#endif
switch (pIrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
return HandleStartDevice(pDO, pIrp );
case IRP_MN_STOP_DEVICE:
return HandleStopDevice( pDO, pIrp );
case IRP_MN_REMOVE_DEVICE:
return HandleRemoveDevice( pDO, pIrp );
default:
// if not supported here, just pass it down
return PassDownPnP(pDO, pIrp);
}
// all paths from the switch statement will "return"
// the results of the handler invoked
}
NTSTATUS PassDownPnP( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp ) {
IoSkipCurrentIrpStackLocation( pIrp );
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDO->DeviceExtension;
return IoCallDriver(pDevExt->pLowerDevice, pIrp);
}
NTSTATUS HandleStartDevice( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp ) {
// The stack location contains the Parameter info
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation( pIrp );
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDO->DeviceExtension;
#if DBG>=1
DbgPrint("WMIEX: StartDevice, Symbolic device #%d\n",
pDevExt->DeviceNumber+1);
#endif
PCM_RESOURCE_LIST pResourceList;
PCM_FULL_RESOURCE_DESCRIPTOR pFullDescriptor;
PCM_PARTIAL_RESOURCE_LIST pPartialList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialDescriptor;
int i;
pResourceList = pIrpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
pFullDescriptor =
pResourceList->List;
pPartialList =
&pFullDescriptor->PartialResourceList;
for (i=0; i<(int)pPartialList->Count; i++) {
pPartialDescriptor =
&pPartialList->PartialDescriptors[i];
switch (pPartialDescriptor->Type) {
case CmResourceTypeInterrupt:
#if DBG>=1
DbgPrint("WMIEX: Presented with Interrupt Resources - "
"ignored");
#endif
break;
case CmResourceTypeDma:
// We don't do DMA - ignore
break;
case CmResourceTypePort:
pDevExt->portBase = (PUCHAR)
pPartialDescriptor->u.Port.Start.LowPart;
pDevExt->portLength =
pPartialDescriptor->u.Port.Length;
#if DBG>=1
DbgPrint("WMIEX: Claiming Port Resources: Base=%X Len=%d\n",
pDevExt->portBase, pDevExt->portLength);
#endif
break;
case CmResourceTypeMemory:
// We don't do memory usage
break;
}
}
// Register as a WMI Participant
IoWMIRegistrationControl( pDO, WMIREG_ACTION_REGISTER);
pDevExt->state = Started;
return PassDownPnP(pDO, pIrp);
}
NTSTATUS HandleStopDevice( IN PDEVICE_OBJECT pDO,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: StopDevice Handler\n");
#endif
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDO->DeviceExtension;
pDevExt->state = Stopped;
return PassDownPnP(pDO, pIrp);
}
NTSTATUS HandleRemoveDevice(IN PDEVICE_OBJECT pDO,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: RemoveDevice Handler\n");
#endif
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDO->DeviceExtension;
// Revoke participation as a WMI Provider
IoWMIRegistrationControl( pDO, WMIREG_ACTION_DEREGISTER);
// This will yield the symbolic link name
UNICODE_STRING pLinkName =
pDevExt->ustrSymLinkName;
// ... which can now be deleted
IoDeleteSymbolicLink(&pLinkName);
#if DBG>=1
DbgPrint("PPORT: Symbolic Link TMRPP%d Deleted\n",
pDevExt->DeviceNumber+1);
#endif
// Delete the device
IoDeleteDevice( pDO );
pDevExt->state = Removed;
return PassDownPnP( pDO, pIrp );
}
//++
// Function: DriverUnload
//
// Description:
// Stops & Deletes devices controlled by this driver.
// Stops interrupt processing (if any)
// Releases kernel resources consumed by driver
//
// Arguments:
// pDriverObject - Passed from I/O Manager
//
// Return value:
// None
//--
VOID DriverUnload (
IN PDRIVER_OBJECT pDriverObject ) {
#if DBG>=1
DbgPrint("WMIEX: DriverUnload\n");
#endif
}
//++
// Function: DispatchWMI
//
// Description:
// Handles call for WMI SYSTEM_CONTROL request
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failuer code
//--
NTSTATUS DispatchWMI (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: WMI SYSTEM_CONTROL requested (DispatchWMI)\n");
#endif
static WMIGUIDREGINFO wmiGuids = {
&GUID_WMIEx, // GUIDS
1, // Number of instances
WMIREG_FLAG_INSTANCE_PDO }; // Flags
static WMILIB_CONTEXT wmiCtx = {
1, // GuidCount
&wmiGuids, // GuidList
DpWmiQueryReginfo,
DpWmiQueryDataBlock,
NULL, // SetWmiDataBlock
NULL, // SetWmiDataItem
NULL, // ExecuteWmiMethod
NULL }; // WmiFunctionControl
SYSCTL_IRP_DISPOSITION disposition;
NTSTATUS status =
WmiSystemControl( &wmiCtx,
pDevObj,
pIrp,
&disposition);
switch (disposition) {
case IrpProcessed:
return status;
case IrpNotCompleted:
// Complete the IRP
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return status;
case IrpNotWmi:
case IrpForward:
default:
return PassDownPnP( pDevObj, pIrp );
}
}
NTSTATUS
DpWmiQueryReginfo(
IN PDEVICE_OBJECT pDevObj,
OUT PULONG pRegFlags,
OUT PUNICODE_STRING InstanceName,
OUT PUNICODE_STRING *pRegistryPath,
OUT PUNICODE_STRING MofResourceName,
OUT PDEVICE_OBJECT *pPdo
) {
#if DBG>=1
DbgPrint("WMIEX: DpWmiQuueryRegInfo\n");
#endif
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
*pRegFlags = WMIREG_FLAG_INSTANCE_PDO;
*pRegistryPath = ®Path;
// MofResourceName is whatever name was used in the
// Resource (.rc) file for the driver project
RtlInitUnicodeString(MofResourceName, L"MofResource");
// Returning the PDO (Physical Device Object) is needed
// since we are requesting auto-naming based on the PDO
*pPdo = pDevExt->pPDO;
return STATUS_SUCCESS;
}
NTSTATUS
DpWmiQueryDataBlock(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp,
IN ULONG GuidIndex,
IN ULONG InstanceIndex,
IN ULONG InstanceCount,
IN OUT PULONG InstanceLengthArray,
IN ULONG BufferAvail,
OUT PUCHAR pBuffer
) {
#if DBG>=1
DbgPrint("WMIEX: DpWmiQueryDataBlock\n");
DbgPrint("WMIEX: GuidIndex = %d, InstanceIndex = %d\n", GuidIndex, InstanceIndex);
DbgPrint("WMIEX: InstanceCount = %d, InstanceLengthArray = %d\n", InstanceCount, InstanceLengthArray);
DbgPrint("WMIEX: BufferAvail = %d, MOF_DATA_SIZE = %d\n", BufferAvail, MOF_DATA_SIZE);
#endif
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
// Do we have enough room for the MOF data?
if ( MOF_DATA_SIZE > BufferAvail )
return WmiCompleteRequest( pDevObj,
pIrp,
STATUS_BUFFER_TOO_SMALL,
MOF_DATA_SIZE,
IO_NO_INCREMENT );
// Stuff Buffer with gathered MOF data (3 ULONGS)
// Simply cast Buffer as MofData structure
// Then let the compiler copy everything
*(PMOFDATA)pBuffer = pDevExt->mofData;
return WmiCompleteRequest( pDevObj,
pIrp,
STATUS_SUCCESS,
MOF_DATA_SIZE,
IO_NO_INCREMENT );
}
//++
// Function: DispatchCreate
//
// Description:
// Handles call from Win32 CreateFile request
// For this driver, does nothing
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failure code
//--
NTSTATUS DispatchCreate (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: DispatchCreate\n");
#endif
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;
if (pDevExt->state != Started)
status = STATUS_DEVICE_REMOVED;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0; // no bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return status;
}
//++
// Function: DispatchClose
//
// Description:
// Handles call from Win32 CreateHandle request
// For this driver, frees any buffer
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failure code
//--
NTSTATUS DispatchClose (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: DispatchClose\n");
#endif
// Dig out the Device Extension from the Device object
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
if (pDevExt->deviceBuffer != NULL) {
ExFreePool(pDevExt->deviceBuffer);
pDevExt->deviceBuffer = NULL;
pDevExt->deviceBufferSize = 0;
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0; // no bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
//++
// Function: DispatchCancel
//
// Description:
// Handles canceled IRP
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failuer code
//--
VOID DispatchCancel (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: IRP Canceled\n");
#endif
// Just complete the IRP
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
IoStartNextPacket( pDevObj, TRUE );
}
//++
// Function: DispatchWrite
//
// Description:
// Handles call from Win32 WriteFile request
// For this driver, starts the device by indirectly
// invoking StartIo
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failuer code
//--
NTSTATUS DispatchWrite (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: Write Operation requested (DispatchWrite)\n");
#endif
// Update MOF data
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
pDevExt->mofData.totalWrites++;
// Start the I/O
IoMarkIrpPending( pIrp );
IoStartPacket( pDevObj, pIrp, 0, DispatchCancel);
return STATUS_PENDING;
}
//++
// Function: DispatchRead
//
// Description:
// Handles call from Win32 ReadFile request
// For this driver, xfers pool buffer to user
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failuer code
//--
NTSTATUS DispatchRead (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG>=1
DbgPrint("WMIEX: Read Operation requested (DispatchRead)\n");
#endif
// Update MOF data
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
pDevExt->mofData.totalReads++;
NTSTATUS status = STATUS_SUCCESS;
PVOID userBuffer;
ULONG xferSize;
// The stack location contains the user buffer info
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation( pIrp );
// Determine the length of the request
xferSize = pIrpStack->Parameters.Read.Length;
// Obtain user buffer pointer
userBuffer = pIrp->AssociatedIrp.SystemBuffer;
// Don't transfer more than the user's request
xferSize = (xferSize < pDevExt->deviceBufferSize) ?
xferSize : pDevExt->deviceBufferSize;
// Now copy the pool buffer into user space
RtlCopyMemory( userBuffer, pDevExt->deviceBuffer,
xferSize );
// Free the temporary pool buffer
ExFreePool( pDevExt->deviceBuffer );
pDevExt->deviceBuffer = NULL;
pDevExt->deviceBufferSize = 0;
// Now complete the IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = xferSize; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return status;
}
//++
// Function:
// TransmitByte
//
// Description:
// This function sends one character to the device
// The polling timer is then started which will
// eventually invoke the PollingTimerDpc.
// If no characters remain to be transmitted, return FALSE.
//
// Arguments:
// Pointer to the Device Extension
//
// Return Value:
// TRUE - one more byte transmitted
// FALSE - no more bytes remain to be transmitted
//--
BOOLEAN TransmitByte(
IN PVOID pArg ) {
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pArg;
// If all the bytes have been sent, just quit
if( pDevExt->xferCount >= pDevExt->maxXferCount)
return FALSE;
// A transfer is happening.
PDEVICE_OBJECT pDevObj =
pDevExt->pDevice;
PIRP pIrp = pDevObj->CurrentIrp;
// Obtain user buffer pointer
PUCHAR userBuffer = (PUCHAR)
pIrp->AssociatedIrp.SystemBuffer;
UCHAR nextByte =
userBuffer[pDevExt->xferCount];
// Now send it...
#if DBG>=1
DbgPrint("WMIEX: TransmitByte: Sending 0x%02X to port %X\n",
nextByte, pDevExt->portBase);
#endif
// Update MOF data
pDevExt->mofData.totalTransfers++;
// The loopback connector requires us to do
// some bizzare work.
// Bit 0 of the data is sent as bit 0 of Port data.
WriteData( pDevExt, nextByte & 1);
// It will be read in Status bit 3
// Bits 1-3 of the data are sent as bits 0,1, & 3
// of the Control register.
// Control bits 0 & 1 are inverted.
UCHAR bits = (nextByte & 0x8) +
((nextByte & 0x6)>>1);
bits ^= 0x3; // Invert the 2 control bits (0 & 1)
// These bits will be read in Status bits 4,5, & 7
WriteControl( pDevExt, bits | CTL_DEFAULT);
// Now read the data from the loopback
UCHAR status =
ReadStatus( pDevExt );
// Format the nibble into the upper half of the byte
UCHAR readByte =
((status & 0x8)<< 1) |
((status & 0x30)<<1) |
(status & 0x80);
pDevExt->deviceBuffer[pDevExt->xferCount++] =
readByte;
#if DBG>=1
DbgPrint("WMIEX: TransmitByte read character: 0x%03X\n",
readByte);
#endif
// Update MOF data
pDevExt->mofData.totalTransfers++;
// Start the polling timer
#if DBG>=2
DbgPrint("WMIEX: TransmitByte starting timer\n");
#endif
KeSetTimer(
&pDevExt->pollingTimer,
pDevExt->pollingInterval,
&pDevExt->pollingDPC );
return TRUE;
}
//++
// Function:
// StartIo
//
// Description:
// This function is responsible initiating the
// actual data transfer. The ultimate result
// should be a started Timer object.
//
// Arguments:
// Pointer to the Device object
// Pointer to the IRP for this request
//
// Return Value:
// (None)
//--
VOID
StartIo(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp
) {
#if DBG>=1
DbgPrint("WMIEX: Start I/O Operation\n");
#endif
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation( pIrp );
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
PUCHAR userBuffer;
ULONG xferSize;
switch( pIrpStack->MajorFunction ) {
// Use a SynchCritSection routine to
// start the write operation...
case IRP_MJ_WRITE:
// Set up counts and byte pointer
pDevExt->maxXferCount =
pIrpStack->Parameters.Write.Length;
pDevExt->xferCount = 0;
// Since we processing a new Write request,
// free up any old buffer
if (pDevExt->deviceBuffer != NULL) {
ExFreePool(pDevExt->deviceBuffer);
pDevExt->deviceBuffer = NULL;
pDevExt->deviceBufferSize = 0;
}
// Determine the length of the request
xferSize =
pIrpStack->Parameters.Write.Length;
// Obtain user buffer pointer
userBuffer = (PUCHAR)
pIrp->AssociatedIrp.SystemBuffer;
// Allocate the new buffer
pDevExt->deviceBuffer = (PUCHAR)
ExAllocatePool( PagedPool, xferSize );
if (pDevExt->deviceBuffer == NULL) {
// buffer didn't allocate???
// fail the IRP
pIrp->IoStatus.Status =
STATUS_INSUFFICIENT_RESOURCES;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
IoStartNextPacket( pDevObj, FALSE );
}
pDevExt->deviceBufferSize = xferSize;
// Try to send the first byte of data.
#if DBG>=1
DbgPrint("WMIEX: StartIO: Transmitting first byte of %d\n", pDevExt->deviceBufferSize);
#endif
TransmitByte( pDevExt );
break;
//
// Should never get here -- just get rid
// of the packet...
//
default:
pIrp->IoStatus.Status =
STATUS_NOT_SUPPORTED;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(
pIrp,
IO_NO_INCREMENT );
IoStartNextPacket( pDevObj, FALSE );
break;
}
}
//++
// Function:
// PollingTimerDpc
//
// Description:
// This function is the DPC routine called
// each time the timer "ticks".
// The routine checks on the device -
// if room available, more data is sent
//
// Arguments:
// Pointer to the Device object
// Pointer to the IRP for this request
//
// Return Value:
// (None)
//--
VOID PollingTimerDpc( IN PKDPC pDpc,
IN PVOID pContext,
IN PVOID SysArg1,
IN PVOID SysArg2 ) {
#if DBG>=1
DbgPrint("WMIEX: PollingTimerDpc Fired\n");
#endif
PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)
pContext;
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
// Try to send more data
if (!TransmitByte( pDevExt ) ) {
// Transfer complete (normal or error)
// Complete the IRP appropriately
#if DBG>=1
DbgPrint("WMIEX: PollingTimerDpc Completing IRP\n");
#endif
PIRP pIrp = pDevObj->CurrentIrp;
pIrp->IoStatus.Information =
pDevExt->xferCount;
// Figure out what the final status should be
pIrp->IoStatus.Status = STATUS_SUCCESS;
// If an error occurred, Status would change
// Now Complete the IRP
IoCompleteRequest( pIrp, IO_PARALLEL_INCREMENT );
// And request another IRP
IoStartNextPacket( pDevObj, FALSE);
}
}